AbstractRoutingDataSource 只支持单库事务,也就是说切换数据源要在开启事务之前执行。 spring DataSourceTransactionManager进行事务管理,开启事务,会将数据源缓存到DataSourceTransactionObject对象中进行后续的commit rollback等事务操作。
出现多数据源动态切换失败的原因是因为在事务开启后,数据源就不能再进行随意切换了,也就是说,一个事务对应一个数据源。
1.传统的Spring管理事务是放在Service业务层操作的,所以更换数据源的操作要放在这个操作之前进行。也就是切换数据源操作放在Controller层,可是这样操作会造成Controller层代码混乱的结果。
故而想到的解决方案是将事务管理在数据持久 (Dao层) 开启,切换数据源的操作放在业务层进行操作,就可在事务开启之前顺利进行数据源切换,不会再出现切换失败了。
2.如果管理事务是放在Service业务层操作的,Spring事务会在方法前获取数据连接connection,动态数据源的切面是在Dao层,但是这时还没有到DAO层进行路由选择,因此需要延迟加载数据源,需要用到LazyConnectionDataSourceProxy
Spring LazyConnectionDataSourceProxy 代理类的源码解析
1、该类的实现思路
(1)、代理了目标数据源 dataSource 的所有方法,其中在 invoke 方法,Spring使用了排除法;
(2)、只有 dataSource 获取到Connection之后,在执行 java.sql.Connection#prepareStatement(java.lang.String) 时候,Spring 才会主动去数据库链接池中获取 Connection ,这样做的好处就是提高数据库链接的使用率和效率;
(3)、据此我们可以看到 Spring 的良苦用心,LazyConnectionDataSourceProxy 经常会被用在一些分库分表、多数据源事务的应用当中;
(4)、多数据源的事务管理解决方案,很多采用了同时开启所有数据源事务、同时提交的策略,例如:阿里的 cobar 解决方案等;
(5)、如果我们的数据源是使用了 LazyConnectionDataSourceProxy 则在执行 Connection#prepareStatement 之前,spring 是不会向数据库连接池获取数据库链接的
3.如果不用LazyConnectionDataSourceProxy,可以给切面类上加上@Order(-1),让此切面优先于事务的切面执行
测试多数据源的时候,获取connection的时机
使用了LazyConnectionDataSourceProxy