spring声明式事务需满足四大前提:类由spring容器管理、方法为public、正确定义事务管理器、启用@enabletransactionmanagement或;默认传播行为为required、隔离级别为数据库默认值,但嵌套调用、幻读防控、超时设置等易踩坑;事务失效主因是代理未生效(如自调用)、异常未触发回滚(仅runtimeexception/error默认回滚)、数据源未关联事务管理器。

Java 事务配置不是“一套模板套所有”,得看用的是哪层框架、什么场景、要不要分布式——核心就三点:声明式怎么写、编程式怎么控、底层数据源和代理机制是否到位。
Spring 声明式事务怎么配?
这是最常用的方式,靠 @Transactional 注解驱动,但光加注解没用,必须满足几个前提:
- 目标类由 Spring 容器管理(不能 new 出来)
- 注解加在 public 方法上(private/protected 不生效)
- 事务管理器 bean 必须正确定义(比如
DataSourceTransactionManager或 JTA 类型) - 启用事务注解驱动:
@EnableTransactionManagement(Java 配置)或<annotation-driven></annotation-driven>(XML)
事务传播行为和隔离级别怎么设?
默认 PROPAGATION_REQUIRED 和数据库默认隔离级别,但高频踩坑点在这儿:
- 嵌套调用时,内部方法也加了
@Transactional,但没设propagation = Propagation.REQUIRES_NEW→ 实际没开新事务 - 读多写少场景想避免幻读,却只设
isolation = Isolation.REPEATABLE_READ,但 MySQL 默认可重复读仍可能幻读 → 得配合 select for update 或升级到串行化 - 超时设置被忽略:没配
timeout = 30(单位秒),大查询卡住时事务不自动回滚
事务不生效?先查这三件事
90% 的“事务失效”问题都出在基础链路上:
- 代理没生效:自调用(同一个类内方法 A 调 B,B 有 @Transactional)→ Spring 代理拦截不到,B 不走事务
-
异常没被捕获:默认只对
RuntimeException和Error回滚,检查是否用了try-catch吞掉了异常,或显式指定了rollbackFor = Exception.class -
数据源没走事务管理器:比如用了多个
DataSource却只配了一个TransactionManager,或 MyBatis 的SqlSessionFactory没关联正确数据源
分布式事务怎么配?
单库事务靠 Spring 就够,跨库/微服务就得升级方案:
-
Seata AT 模式:需要引入
seata-spring-boot-starter,配置file.conf和registry.conf,业务方法加@GlobalTransactional - 本地消息表 + 定时补偿:适合强一致性要求不高、系统已稳定运行的场景,关键是要把发消息和改状态放在同一本地事务里
- Saga 模式:适合长流程(如下单→扣库存→发物流→通知用户),每个步骤要有正向操作 + 对应补偿操作,靠状态机或事件驱动协调
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











