我的需求是单线程切换数据源,对于每一个service方法都是只访问一个数据源(@DS注解写在方法上动态取参数值),在controller层中取调用多个service方法,以达到切换数据源的目的,但是又一个问题,这样子在service上无法启用事务注解,若启用事务注解则@DS注解失效,根据官方项目中的WIKI中没有找到解决的方案,只是说多数据源操作不能开启事务。但是我并不是多数据源事务,我只是单个service方法保证事务一致即可。
之后就是定位问题,加事务不好使那么一定是事务出了问题,开启debug模式....
首先由于 service注解上
@transactional-->
TransactionInterceptor.interpter()-->
TransactionAspectSupport.createTransactionIfNecessary()-->
AbstractPlatformTransactionManager.getTransaction()-->
DataSourceTransactionManager.doBegin()-->
AbstractRoutingDataSource.determineTargetDataSource()[lookupKey==null去拿默认的Datasource, 不为空则使用获取到的连接]
-->
DataSourceTransactionManager.setTransactional()[将连接设置到TransactionUtils的threadLocal中]--->
Repository@Annotation-->
执行一般调用链,
问题在于DataSourceTransactionManager.doBegin()的方法中里面中
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { Connection newCon = obtainDataSource().getConnection(); if (logger.isDebugEnabled()) { logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction"); } txObject.setConnectionHolder(new ConnectionHolder(newCon), true); } txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
在txObject.hasConnectionHolder()判断的时候若当前线程之前有过一次操作,那么不会新连接。。。
那么咋解决呢? @EnableTransactionManagement 注解,spring5.x提供给我们自动配置事务的一个注解这个注解类上面有描述我接取一段你感受下。。。
* <p>For those that wish to establish a more direct relationship between * {@code @EnableTransactionManagement} and the exact transaction manager bean to be used, * the {@link TransactionManagementConfigurer} callback interface may be implemented - * notice the {@code implements} clause and the {@code @Override}-annotated method below: * * <pre class="code"> * @Configuration * @EnableTransactionManagement * public class AppConfig implements TransactionManagementConfigurer { * * @Bean * public FooRepository fooRepository() { * // configure and return a class having @Transactional methods * return new JdbcFooRepository(dataSource()); * } * * @Bean * public DataSource dataSource() { * // configure and return the necessary JDBC DataSource * } * * @Bean * public PlatformTransactionManager txManager() { * return new DataSourceTransactionManager(dataSource()); * }
这不就是我们要的么。。。
之后我默默的加上了一个配置类问题解决了。。
这个东西是我看一个人的博客里看到的,附上地址
package com.bonc.ioc.core.config; import com.bonc.ioc.core.util.SpringContextHolder; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @Slf4j public class MyDataSourceTransactionManagerAutoConfiguration extends DataSourceTransactionManagerAutoConfiguration { /** * 自定义事务 * MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。 * @return */ @Bean(name = "transactionManager") public DataSourceTransactionManager transactionManagers() { log.info("-------------------- transactionManager init ---------------------"); return new DataSourceTransactionManager(SpringContextHolder.getBean("dataSource")); } }