事务不生效问题分析

Scroll Down

问题现象:
Manager层标记事务注解,事务不生效,抛出异常后,持久化数据无法回滚。

问题原因:
是因为事务管理器和mybatis配置的数据源不一致,导致声明式事务管理的连接,与真正执行SQL的连接不一致,进而导致事务不生效。

1、开始事务的时候数据库连接池及获取到的连接如下:
(1)连接池
image
(2)连接
image-1648175656845
2、SqlSessionTemple实际执行的时候
image-1648175673488
因为在事务管理器中没有获取到对应SqlSessionFactory对应的SqlSession,所以会新开启一个SqlSession
此时会获取当前SqlSessionFactory的数据源来开启SqlSession
image-1648175681765
image-1648175689349
可以看到,现在真正mybatis的数据库连接池已经不是开始事务的时候所使用的数据库连接池了。
跟踪到mybatis的BaseExecutor执行器中
image-1648175697574
image-1648175703817
可以看到此时真正执行SQL的连接已经换成了一个新的连接,与之前事务开启的连接不是同一个。也就是说,当前事务场景下,事务开启的连接一直处于闲置状态,即使出现异常也无法回滚,更不可能在事务中commit,此时数据之所以依然还能持久化是因为数据库连接池在设置连接的提交是设置了自动提交autoCommit=true。

在DataSource相同的时候是这样的:

1、开启事务的时候数据库连接池
image-1648175711537
2、实际连接
image-1648175717408
到了Mybatis中获取连接的时候
image-1648175724561
image-1648175732335
关键代码是在下面,事务管理器通过数据源实例来获取连接,在同一个线程环境下如果数据源不发生变化,会重用事务管理器中的已开启的连接。如果数据源发生变化,那么会重新生成一个数据库连接。
image-1648175739553
可以看到,当数据源配成一致的时候这个问题就不存在了。
mybatis的数据源和Spring事务的数据源如果指定不一致,就会出现这种情况。