Transaction事务注解和DynamicDataSource动态数据源切换问题解决

 

问题描述: 写主库开事务的状况下会致使时不时的将更新/插入操做写入到从库上, 致使mysqlException update command deniedmysql

 
问题缘由: jetty的工做队列会重用处理线程, 致使threadLocal中的值被重用, 然而transaction注解在service层, 他会在DynamicDataSourceSwitch被设置以前直接去threadlocal拿数据, 本应拿到null, 可是拿到了以前线程的值
 
通常代码调用链:
Repository@Annotation(AOP)-->DefaultSqlSession-->SimpleExecutor-->BaseExecutor.getConnection()-->SpringManagedTransaction.getConnection()--->链接为空-->AbstractRoutingDataSource.getConnection()-->拿到beforeAOP中注入的datasource的key, 因此每次都会动态切换数据源
 
事务代码调用链:
service注解上@transactional--> TransactionInterceptor.interpter()-->TransactionAspectSupport.createTransactionIfNecessary()-->AbstractPlatformTransactionManager.getTransaction()-->DataSourceTransactionManager.doBegin()-->AbstractRoutingDataSource.determineTargetDataSource()[lookupKey==null去拿默认的Datasource, 不为空则使用获取到的链接]-->DataSourceTransactionManager.setTransactional()[将链接设置到TransactionUtils的threadLocal中]--->Repository@Annotation-->执行通常调用链, 问题在于SpringManagedTransaction.getConnection()-->openConnection()-->DataSourceUtils.getConnection()-->TransactionSynchronizationManager.getResource(dataSource)不为空[从TransactionUtils的threadLocal中获取数据源], 因此不会再去调用DynamicDataSource去获取数据源
 

有时间再补一个Sequence图sql

 
问题解决, DataSourceAdvice AfterReturn须要删除threadLocal中的数据源key 
 
public class DataSourceAdvice
implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {

private static final Logger LOG = LoggerFactory.getLogger(DataSourceAdvice.class);

@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target)
throws Throwable {
DataSourceSwitcher.clearDataSource();
}

}
相关文章
相关标签/搜索