@Transcational 是 Spring 中声明式事务管理的注解
通俗来讲就是用了 @Transcational 当 sql 语句每条执行后,遇到错误不会回滚,但是用了这个歌注解之后 sql 会回滚
一般用法
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private StockMapper stockMapper; @Transactional // 开启事务 public void createOrder(Order order) { // 1. 保存订单 orderMapper.insert(order); // 2. 扣减库存 stockMapper.deduct(order.getProductId(), order.getQuantity()); // 3. 如果这里抛出异常,订单和库存都会回滚 } }事务传播行为(最常用的配置)
| 传播级别 | 值 | 说明 | 使用场景 |
|---|---|---|---|
| REQUIRED | 默认 | 有事务就用当前的,没有就新建 | 大部分业务方法 |
| REQUIRES_NEW | 总是新建 | 挂起当前事务,新建一个独立事务 | 日志记录、独立子任务 |
| SUPPORTS | 有就用,没有就不用 | 不需要事务的方法 | 只读查询 |
| MANDATORY | 必须有事务 | 强制要求调用方有事务 | 核心业务方法 |
| NOT_SUPPORTED | 不用事务 | 挂起当前事务 | 非关键操作 |
| NEVER | 必须没有事务 | 禁止在事务中执行 | 某些特殊操作 |
| NESTED | 嵌套事务 | 内层事务回滚不影响外层 | 批量处理(部分回滚) |
@Transactional // 默认 REQUIRED public void methodA() { // 有事务 methodB(); // 会加入 methodA 的事务 } @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB() { // 新建独立事务,methodA 的回滚不影响 methodB }事务隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
|---|---|---|---|---|
| READ_UNCOMMITTED | ✅ | ✅ | ✅ | 读未提交(最低) |
| READ_COMMITTED | ❌ | ✅ | ✅ | 读已提交(Oracle默认) |
| REPEATABLE_READ | ❌ | ❌ | ✅ | 可重复读(MySQL默认) |
| SERIALIZABLE | ❌ | ❌ | ❌ | 串行化(最高,最慢) |
// 默认:RuntimeException 和 Error 触发回滚,Exception(受检异常)不触发 @Transactional public void method() { // SQLException 不会触发回滚 } // 指定回滚的异常类型 @Transactional(rollbackFor = Exception.class) // 所有异常都回滚 public void method() { // SQLException 也会触发回滚 } // 指定不回滚的异常 @Transactional(noRollbackFor = IllegalArgumentException.class) public void method() { // IllegalArgumentException 不会触发回滚 }常见陷阱
| 陷阱 | 说明 | 解决方案 |
|---|---|---|
| 同类方法调用无效 | 同一个类中,无事务方法调用事务方法,事务不生效 | 注入自身或把方法分开 |
| private 方法无效 | @Transactional不能用在 private 方法上 | 使用 public |
| 异常被 catch 了 | 自己 catch 异常后不抛出,事务不回滚 | 重新抛出或手动回滚 |
| 数据库引擎不支持 | MyISAM 引擎不支持事务 | 使用 InnoDB |