内容纲要
💡 一、@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、消息补偿等机制 |
🧩 三、事务生效的几个条件
-
必须由 Spring 管理的 Bean 调用(即通过代理对象调用)。
👉 同类中自调用不会触发事务。this.innerMethod(); // 无事务 service.innerMethod(); // 有事务 -
抛出运行时异常才会回滚
- 默认只对
RuntimeException或Error回滚。 -
如果想对检查异常(如
IOException)也回滚,要配置:@Transactional(rollbackFor = Exception.class)
- 默认只对
-
事务传播机制
比如REQUIRED、REQUIRES_NEW、NESTED等,常见于复杂调用链:@Transactional(propagation = Propagation.REQUIRES_NEW)
💥 四、多个数据库的情况
如果你的系统中涉及多个数据源(比如 MySQL + PostgreSQL),
@Transactional 默认 只能管理单数据源 的事务。
也就是说:
- 同一个事务中操作两个不同数据源的表时,Spring 默认不能保证原子性。
-
解决方案有:
- 使用 JTA 分布式事务管理器(如 Atomikos、Bitronix);
- 使用 Seata、Narayana 等分布式事务框架;
- 设计补偿机制(最终一致性);
- 拆分成异步流程,用消息队列保证一致性。
✅ 五、实战小结
| 使用时机 | 示例 |
|---|---|
| 本地单库的多步写操作 | 订单生成、扣库存、扣余额 |
| 多DAO操作同库 | 业务聚合逻辑 |
| 需要失败自动回滚 | 异常中止、数据库连接断开 |
| 不适合使用 | 跨服务调用、异步任务、多个数据源 |
一图看懂 @Transactional 的执行与回滚机制
注意事项
- 同类中自调用无效
- 默认仅RuntimeException触发回滚
- 异步线程中事务无效
- 多数据源需分布式事务
