關于@DS注解切換數據源失敗的原因實戰(zhàn)記錄
項目場景:
一位好友在陳年老代碼中想要加入mybatis-plus和boumidou的多數據源來輕松實現crud,但是發(fā)現@DS無法成功切換數據源,一直都是訪問的主庫,于是我開始了漫長的啃源碼找原因。
以下內容包含兩個問題1:配置的數據庫沒有正常被dynamic框架載入,2:@DS注解切換數據源無效
問題排查過程
第一個問題,數據源沒有載入
根據啟動日志里druid打印的信息來看,只載入了一個數據庫,并沒有把yml配置信息中的兩個數據庫都加載,YML配置如下。
從源碼來看,數據源的配置讀取是在AbstractDataSourceProvider類中。
他的調用是在子類YmlDynamicDataSourceProvider中。
然后在DynamicDataSourceAutoConfiguration類中注入了YmlDynamicDataSourceProvider。
在此處打上斷點后,發(fā)現傳入的datasourceMap中的信息都是正確的,跟yml配置的一致。
那就只能是YmlDynamicDataSourceProvider中的loadDataSources()方法沒有調用。
此方法在DynamicRoutingDataSource的初始化方法中調用。
在這里打上斷點后發(fā)現斷點進不來,是對象沒有創(chuàng)建的原因,回到DynamicDataSourceAutoConfiguration類中找DynamicRoutingDataSource的創(chuàng)建。
@ConditionalOnMissingBean表明dataSource這個Bean應該是已經被注入了,通過全局查詢找到了問題的關鍵點(下圖),代碼在其他地方注入了dataSource。
然而很多地方已經在用這個dataSource了,刪了的話,就雪崩了??紤]另辟蹊徑,選擇了自己去創(chuàng)建DynamicRoutingDataSource對象。
到這里,成功載入了其他數據源。
第二個問題,@DS注解切換數據源無效
先從@DS的攔截盤起,@DS的攔截在DynamicDataSourceAnnotationInterceptor攔截器中,讀取了@DS上的庫名,然后放入一個上下文管理器的隊列中。
調用SQL時,會通過AbstractRoutingDataSource的getConnection()方法(下圖)。
里面的determineDataSource()方法由子類DynamicRoutingDataSource實現,真正切換了數據源,里面調用了隊列的peek()方法,取出上面攔截器中加入的@DS屬性的庫名,然后通過庫名,拿到了對應數據源的DataSource,再結合AbstractRoutingDataSource的getConnection()方法拿到了對應數據庫的連接,去執(zhí)行SQL。
切換數據源的流程到這就說的差不多了,然后講講這個項目中為什么切換不了數據源。
在determineDataSource()方法打上斷點,結果根本沒有經過該方法,然而@DS的攔截器斷點是能正常進入的,@DS注解上的數據源名稱也讀取正確,是第二個庫。由此猜測,應該是沒有走進AbstractRoutingDataSource的getConnection()方法,查看druid的數據庫加載相關的日志,發(fā)現在boumidou的dynamic框架加載數據庫之前,已經有其他數據庫加載了。
推測可能是由于,SQL調用的時候,默認是用的第一個數據庫的DataSource調用的getConnection()方法,但是這個不是由dynamic框架加載,并不是AbstractRoutingDataSource對象,所以不會走進determineDataSource()方法去選擇數據源,就試著想辦法讓dynamic框架優(yōu)先加載。
在上面自己創(chuàng)建DynamicRoutingDataSource的@Bean方法上,加上了@Primary注解,去掉了引起問題一的方法上的@Primary注解,來讓多數據源優(yōu)先加載。
然后就成功了,也能通過@DS正常切換數據源了。
總結
到此這篇關于關于@DS注解切換數據源失敗的原因的文章就介紹到這了,更多相關@DS注解切換數據源失敗內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
spring?aop?pointcut?添加多個execution方式
這篇文章主要介紹了spring?aop?pointcut?添加多個execution方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Java并發(fā)編程中的CyclicBarrier使用解析
這篇文章主要介紹了Java并發(fā)編程中的CyclicBarrier使用解析,CyclicBarrier從字面意思上來看,循環(huán)柵欄,這篇文章就來分析下是到底是如何實現循環(huán)和柵欄的,需要的朋友可以參考下2023-12-12MyBatis的<foreach>以及java代碼的批處理方式
這篇文章主要介紹了MyBatis的<foreach>以及java代碼的批處理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08Java實現的二叉樹常用操作【前序建樹,前中后遞歸非遞歸遍歷及層序遍歷】
這篇文章主要介紹了Java實現的二叉樹常用操作,包括二叉樹的前序建樹,前中后遞歸非遞歸遍歷及層序遍歷等相關操作技巧,需要的朋友可以參考下2018-01-01