一 事务基础:Spring事务工作原理
1 在探讨Spring事务的工作原理时,我们需要注意到事务的核心机制:
@Transactional
public void businessMethod() {
// 业务操作
}
2 Spring通过AOP代理在方法执行步骤:
- 获取数据库连接
- 关闭自动提交(
setAutoCommit(false)) - 执行目标方法
- 根据结果提交或回滚
二 SpringBoot事务失效七种场景
1 事务方法使用非public时,非public方法无法被代理拦截,导致事务失效。
@Component
public class OrderService {
// 非public方法
@Transactional
protected void createOrder(Order order) {
orderDao.save(order);
inventoryDao.deduct(order.getProductId(), order.getQuantity());
}
}
导致结果:库存扣减异常时订单数据仍被保存
2 同类中方法updateUser(无事务注解)调用方法saveUser(有事务注解)的自调用问题,由于代理机制失效,事务不生效
@Service
public class UserService {
public void updateUser() {
this.saveUser(); // 自调用
}
@Transactional
public void saveUser() {
// 数据库操作
}
}
导致结果:即使抛出异常,支付记录仍被保存
3 非事务方法调用事务方法
// 若父类方法未开启事务,调用子类@Transactional方法时,代理失效
public class BaseService {
public void execute() {
save(); // 事务失效
}
@Transactional
public void save() {}
}
解决方案
• 将事务注解添加到父类方法。
• 避免通过继承层级调用事务方法。
导致结果:非事务方法execute,save失效
4 异常类型未被捕获也可能导致事务失效。
Spring默认仅回滚RuntimeException和Error,若抛出其他异常(如IOException)且未配置rollbackFor,事务不会回滚。

@Transactional
public void processData() throws IOException {
try {
for(DataItem item : batch.getItems()) {
dataDao.save(item); // 可能抛出IOException
}
} catch (IOException e) {
log.error("导入失败", e);
}
}
导致结果:部分数据失败时已保存数据未回滚
解决方案
明确指定回滚异常类型:
@Transactional(rollbackFor = Exception.class)
5 传播行为的配置错误
REQUIRES_NEW嵌套使用时,内层事务失败可能不影响外层事务
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
innerMethod(); // 内层事务独立提交
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
// 操作失败但outerMethod继续执行
}
导致结果:内层事务成功,但外层继续执行(无回滚)
解决方案:
// 需要事务参与
@Transactional(propagation = Propagation.REQUIRED)
// 新事务(独立提交回滚)
@Transactional(propagation = Propagation.REQUIRED)
6 多数据源未指定事务管理器
// 多数据源环境下未明确指定transactionManager,导致事务绑定到默认管理器。
@Transactional // 默认使用primary事务管理器
public void saveToSecondaryDB() {
// 操作secondary数据源
}
解决方案
// 注解中指定事务管理器
@Transactional("secondaryTransactionManager")
7 多线程调用失败
@Transactional
public void batchProcess(List<Item> items) {
items.parallelStream().forEach(item -> {
// 多线程处理
processItem(item); // 包含数据库操作
});
}
导致结果:部分线程失败导致数据不一致
解决方案
- 线程池任务中的事务边界
- @Async异步方法的事务隔离
- 分布式锁与事务的协调问题
8 数据库引擎不支持
MySQL表使用MyISAM引擎
@Transactional
public void logOperation(String operation) {
auditLogDao.save(new AuditLog(operation));
throw new RuntimeException("模拟异常");
}
导致结果:异常发生后日志记录仍被保存
三 排查与解决方案
1 诊断工具
- 开启事务调试日志,预发环境开启spring.jpa.show-sql=true验证事务边界
- 使用AOP监控切面,生产环境部署事务监控,实时追踪事务提交/回滚率
- 事务状态检查工具类,定期进行事务专项压测,验证高并发场景下的事务行为
- 在开发阶段使用@Transactional的timeout属性暴露潜在死锁
2 编码规范建议
- 统一异常处理策略
- 避免同类自调用
- 显式指定rollbackFor
3 架构层面优化
- 分布式事务方案选型
- 事务与缓存的一致性设计
- 长事务拆分策略
4 最佳实践总结
- 事务注解使用检查清单
- 常见反模式示例
- 性能与一致性的平衡建议