Spring JdbcTemplate+@Transactional多数据源事务内读写不一致问题
问题原因拆解
生产环境读不到的核心原因
生产环境主库和从库是完全独立的数据库实例:
- 你加的
@Transactional只负责管理主数据源的事务,jdbcTemplateMaster.update()的修改在方法结束前都处于未提交状态,仅存在于主库当前事务的专属连接中,其他任何连接(包括从库的连接)都无法访问到这些未提交的数据。 - 就算事务最终提交,主从同步也存在天然延迟,从库无法立刻获取主库的最新数据,所以生产环境必然读不到事务内刚写入的数据。
测试环境时有时无的原因
测试环境主从指向同一个数据库,但两个JdbcTemplate绑定的是不同的DataSource Bean——对应两个独立的Hikari连接池:
- Spring的事务绑定是按数据源维度实现的,
@Transactional只会把主数据源的连接绑定到当前线程,jdbcTemplateSlave会从自己的连接池获取独立连接执行查询,和主库的事务完全无关。 - 数据库默认采用
READ_COMMITTED隔离级别,主库事务内未提交的修改,在从另一个独立连接查询时是不可见的,这就是"读不到"的场景; - 偶尔能读到的情况,大概率是以下特殊场景导致:
- 事务提前提交:比如方法内触发异常,事务回滚前触发了隐式提交,或者存在手动调用事务提交的操作;
- 连接池极端复用:测试环境连接池配置过小,导致
jdbcTemplateSlave恰好复用了主库事务正在使用的连接(概率极低,毕竟是两个独立连接池); - 隔离级别被修改:测试库被临时设置为
READ_UNCOMMITTED,允许读取未提交的脏数据。
关键核心结论
Spring的@Transactional无法跨多个DataSource管理全局事务,你当前的写法中,主库写入和从库读取是两个完全独立的操作,不存在事务一致性保证。要实现事务内读写一致,可选方案包括:
- 事务内统一使用主库的
JdbcTemplate执行查询; - 引入分布式事务框架(如Seata)管理多数据源事务;
- 调整业务逻辑,等待事务提交完成后再执行从库查询(需容忍主从同步延迟)。
内容的提问来源于stack exchange,提问作者Manish Kumar
相关产品推荐
相关产品推荐

