Transaction事務注解和DynamicDataSource動態數據源切換問題解決


 

問題描述: 寫主庫開事務的情況下會導致時不時的將更新/插入操作寫入到從庫上, 導致mysqlException update command denied

 
問題原因: 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圖

 
問題解決, 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();
}

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM