Spring Boot不同版本下@Transactional事务行为不一致问题咨询
事务行为差异的核心原因分析
出现这种差异主要是Spring事务执行逻辑、数据库交互细节、版本特性这几个层面的不同导致的,具体拆解如下:
1. 事务传播行为的实际生效逻辑不同
你演示项目里的三个方法应该是在同一个类中吧?Spring默认的动态代理AOP有个关键特点:同一个类内部的方法调用不会触发代理逻辑。也就是说,dummyMethod上的@Transactional是生效的,但它内部调用的doingDBstuff和doingDBstuff1上的@Transactional其实没起作用——整个流程从头到尾都在同一个事务里,插入的修改在当前事务内天然可见,所以后续查询能拿到数据。
而你的旧项目(Spring Boot 1.5)可能存在两种情况:
- 配置了AspectJ静态代理(而非默认动态代理),使得内部方法的
@Transactional真的生效了。如果这些方法的事务传播行为是REQUIRES_NEW,那插入操作会在独立事务里提交,但如果后续查询是在另一个未关联的事务里,或数据库隔离级别限制,就可能看不到; - Spring 4.3(Boot1.5依赖的Spring版本)对事务同步的处理不够完善,导致
JdbcTemplate的插入和查询没绑定到同一个数据库连接上——用了不同连接的话,未提交的事务数据自然查不到。
2. MySQL与JDBC驱动的版本差异
- MVCC细节调整:MySQL 5.7和8.2的默认隔离级别都是
REPEATABLE READ,但8.2对MVCC(多版本并发控制)的实现做了优化,确保同一个事务内的读写能更稳定地看到自身修改;而5.7在某些边界场景下(比如未命中索引的查询),可能会触发快照读,导致看不到当前事务的插入数据。 - JDBC驱动行为差异:MySQL 5.7常用的驱动是5.1.x系列,8.0.x驱动对事务的处理逻辑更严谨,比如对连接的事务绑定更可靠,不会出现同一个事务内切换连接的情况。
3. 连接池的默认配置差异
Spring Boot 1.5默认用的是Tomcat JDBC连接池,而2.7默认用HikariCP。不同连接池对事务的管理逻辑不同:
- Tomcat JDBC在某些场景下可能会复用未正确解绑事务的连接,导致查询操作使用了没有当前事务修改的旧连接;
- HikariCP对事务的绑定更严格,确保同一个事务内的所有操作都用同一个连接,自然能看到插入的数据。
快速验证方向
如果要确认具体原因,可以做这几件事:
- 检查两个项目的事务隔离级别:执行
SELECT @@transaction_isolation;对比; - 验证事务是否共用同一个连接:在插入和查询前后打印连接的哈希值,看是否一致;
- 检查旧项目的AOP代理方式:看是否配置了AspectJ静态代理;
- 确认
JdbcTemplate的数据源和事务管理器的数据源是否一致。
内容的提问来源于stack exchange,提问作者Manish Kumar
相关产品推荐
相关产品推荐

