原本想用springboot+mybatis做多數據源的切換方案,想通過借鑑網上現有的方案,結果搜索後大量都是使用AbstractRoutingDataSource多數據源方案,通過實踐後,發現如果聲明瞭事務,將會在事務內部切換數據源失敗。結果,就是debug,看源碼找原因。下面是springboot+mybatis的調用棧,如果有點功力的同學們一看就知道了。
存在transaction情況下
@Transactional切面切入攔截
DataSourceTransactionManager
doBegin
從threadlocal holder中獲取connection
獲取不到
獲取連接
AbstractRoutingDataSource#getConnection
封裝holder,存入threadLocal中,key爲AbstractRoutingDataSource
獲取到,不再AbstractRoutingDataSource#getConnection
此時,已經獲取到connection,如果@Transactional註解還有切換數據源的切面,則使用切面中切換好的數據源,如果沒有其他註解,則獲得配置的defaultDataSource的數據源。
======================= step2 ===============================
之後,調用mybatis的mapper
mybatis
Executor
prepareStatement
getConnection()
SpringManagedTransaction
getConnection()
查看threadLocal中,key爲AbstractRoutingDataSource,取出connection的holder
如果有用holder裏面的connection
如果沒有從AbstractRoutingDataSource獲取新的連接
======================= step3 ====================================
@Transactional註解的方法中還在調用其他需要切換數據源的service或者方法
仍然走step2,由於從threadLocal可以獲取到connection,所以不會從AbstractRoutingDataSource獲取新的連接,也就是切換數據源失敗
這裏的AbstractRoutingDataSource#getConnection方法是切換數據源的關鍵。如果在事務過程中,我們mybatis每次都是獲取threadlocal中key爲AbstractRoutingDataSource的connection,則不會再調用AbstractRoutingDataSource中的getConnection方法切換數據源。
如果想解決這個問題,自定義吧。。。