java
技术随笔
Spring Boot 事务管理:@Transactional 用法、回滚规则与常见坑
Spring 通过 @Transactional 声明式事务管理,让方法要么全部成功、要么整体回滚,避免“扣了钱没下单”这类半成品数据。下面以 Spring Boot + MyBatis 为例说明用法与坑点。
一、基础用法
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Transactional
public void createOrder(Order order) {
orderMapper.insert(order);
// 若下面抛异常,上面的 insert 会回滚
int i = 1 / 0;
}
}
二、回滚规则
- 默认只在运行时异常(RuntimeException) 和 Error 时回滚;受检异常(checked exception)不会回滚。
- 要让所有异常都回滚,显式声明:
@Transactional(rollbackFor = Exception.class)。 - 手动回滚:在 catch 中调用
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。
三、传播行为(Propagation)
| 传播行为 | 说明 |
|---|---|
| REQUIRED(默认) | 有事务则加入,没有则新建 |
| REQUIRES_NEW | 挂起当前事务,新建独立事务 |
| NESTED | 在当前事务内嵌一个子事务,可单独回滚 |
| SUPPORTS / NOT_SUPPORTED / NEVER | 分别按需“支持/不支持/禁止”事务 |
四、常见坑点
- 自调用失效:同一个类里 A 方法调用带
@Transactional的 B 方法,事务不生效(代理未介入),应拆到不同 Bean。 - 注解加在私有方法或内部调用上无效;应加在 public 方法上。
- 数据库引擎不支持事务:MySQL 的 MyISAM 不支持事务,需用 InnoDB。
- 事务范围过大:长事务占用连接、易锁等待,只把必要的写操作放进事务。
- 异常被 catch 吞掉且不手动回滚,事务会“以为成功”而提交。