什么时候使用@Transactional

内容纲要

💡 一、@Transactional 的作用

@Transactional 是 Spring 提供的声明式事务管理注解
它的核心作用是——在一段方法执行中,保证多个数据库操作要么全部成功,要么全部失败(回滚)

典型场景:

@Transactional
public void transfer(String from, String to, BigDecimal amount) {
    accountDao.debit(from, amount);   // 扣钱
    accountDao.credit(to, amount);    // 加钱
}

如果第二步抛出异常,第一步的扣钱操作也会被回滚。


⚙️ 二、什么时候需要使用 @Transactional

场景 是否推荐加 @Transactional 原因说明
只有一个简单的查询操作 ❌ 不需要 查询本身不影响数据,无需事务
只有一条 INSERT/UPDATE/DELETE ✅ 建议(但非必须) 数据可能出现异常中断,事务能自动回滚
多个写操作(增删改) ✅ 必须 确保一致性,避免部分成功部分失败
调用多个 DAO 层方法 ✅ 必须 跨DAO操作需要事务来保障原子性
异步线程中执行 ⚠️ 无效 Spring事务无法传播到新线程中,需要手动管理或用消息队列
跨服务调用(RPC、HTTP) ⚠️ 无效 分布式事务需用Seata、TCC、消息补偿等机制

🧩 三、事务生效的几个条件

  1. 必须由 Spring 管理的 Bean 调用(即通过代理对象调用)。
    👉 同类中自调用不会触发事务。

    this.innerMethod(); // 无事务
    service.innerMethod(); // 有事务
  2. 抛出运行时异常才会回滚

    • 默认只对 RuntimeExceptionError 回滚。
    • 如果想对检查异常(如 IOException)也回滚,要配置:

      @Transactional(rollbackFor = Exception.class)
  3. 事务传播机制
    比如 REQUIREDREQUIRES_NEWNESTED 等,常见于复杂调用链:

    @Transactional(propagation = Propagation.REQUIRES_NEW)

💥 四、多个数据库的情况

如果你的系统中涉及多个数据源(比如 MySQL + PostgreSQL),
@Transactional 默认 只能管理单数据源 的事务。
也就是说:

  • 同一个事务中操作两个不同数据源的表时,Spring 默认不能保证原子性。
  • 解决方案有:

    1. 使用 JTA 分布式事务管理器(如 Atomikos、Bitronix);
    2. 使用 Seata、Narayana 等分布式事务框架
    3. 设计补偿机制(最终一致性)
    4. 拆分成异步流程,用消息队列保证一致性

✅ 五、实战小结

使用时机 示例
本地单库的多步写操作 订单生成、扣库存、扣余额
多DAO操作同库 业务聚合逻辑
需要失败自动回滚 异常中止、数据库连接断开
不适合使用 跨服务调用、异步任务、多个数据源

一图看懂 @Transactional 的执行与回滚机制

注意事项

  • 同类中自调用无效
  • 默认仅RuntimeException触发回滚
  • 异步线程中事务无效
  • 多数据源需分布式事务

Leave a Comment

您的电子邮箱地址不会被公开。 必填项已用*标注

close
arrow_upward