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();
}

}
相關文章
相關標籤/搜索