java事务需串联mysql隔离级别、spring传播机制与jvm事务上下文:mysql保障数据一致性(如脏读、不可重复读),spring控制代码执行边界(如方法间事务复用),二者协同但易因配置错位出问题;须动手验证各隔离级别现象与sql表现,以及required、requires_new等传播行为在调用链中的实际效果,并注意this调用绕过代理、private方法无效、异常类型默认限制等关键细节。

Java事务深度复习不是罗列概念,而是把MySQL隔离级别、Spring传播机制、JVM中事务上下文三者串起来理解。重点抓“什么场景下会出问题”和“为什么这样设计能解决问题”。
先理清事务的两个层次
数据库事务(MySQL)管的是数据一致性,比如读到没提交的数据(脏读)或两次读结果不同(不可重复读);Spring事务管的是代码执行边界,比如方法A调用方法B时,B要不要跟A共用一个事务。两者协同工作,但出问题时往往是因为没对齐——比如MySQL设了可重复读,但Spring用了REQUIRES_NEW,结果B的修改对A不可见,却误以为是隔离级别导致的。
对照着练隔离级别+现象+SQL验证
别只背定义,每种隔离级别都配一段可运行的SQL测试:
- 读未提交:开两个MySQL客户端,事务A更新但不提交,事务B立刻查到新值——这就是脏读
- 读已提交:事务A更新并提交,事务B在A提交后才查,才能看到变化——解决了脏读,但可能不可重复读
- 可重复读(InnoDB默认):事务B第一次查id=1是name='张三',A改完提交,B再查还是'张三'——MVCC快照起作用
- 可串行化:事务B查范围select * from user where age>20,A在此区间插入新记录并提交,B再查行数不变——加了间隙锁
Spring传播机制要结合调用链看
写两个带@Transactional的方法,手动触发不同传播行为:
- REQUIRED(默认):A方法开启事务,调用B方法,B复用A的事务——A回滚,B也一起回滚
- REQUIRES_NEW:A开启事务,调用B,B挂起A、新建事务——B回滚不影响A,A回滚也不影响B已提交的数据
- NESTED:A开启事务,B作为嵌套事务,有独立的保存点——B回滚可撤回到保存点,A回滚则全部清除
- SUPPORTS:B方法本身没事务,被A调用就加入A;单独运行就是非事务——适合日志类无副作用操作
关键细节必须动手验证
这些地方容易想当然,一定要写代码跑一遍:
- 同一个Service内,this.methodB()调用不会触发事务代理(因为绕过了Spring AOP),必须通过接口注入或ApplicationContext.getBean()调用
- @Transactional只对public方法生效,private/protected方法加了也无效
- 异常类型默认只回滚RuntimeException及其子类,检查Exception需显式配置rollbackFor
- 事务方法内try-catch吞掉异常,且没重新抛出,会导致事务不回滚
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











