sqlhelper整合dynamic多資料來源的分頁問題(非教學向)
一.問題描述
最近接手(頂鍋)了公司的框架維護工作,第一項任務就是整合dynamic多資料來源框架。(dynamic官方使用文件,本文不是教學,有興趣的小夥伴可以自己查閱文件)。整合dynamic之後,一切都很順利,但是測試到SQLHelper框架的分頁功能,出錯了:SQLHelper分頁功能,全部是按照dynamic指定的primary資料來源來處理分頁sql的。比如我配置了mysql和oracle兩個資料來源,並且指定mysql為primary主資料來源,然後不管使用哪個資料來源進行查詢,SQLHelper都是按照primary指定的主資料來源mysql進行分頁處理,導致用oracle資料來源時分頁語句sql報錯。
二.解決思路
1.找到分頁sql的處理入口
通過斷點除錯,找到了SQLHelper的com.jn.sqlhelper.dialect.internal.Dialect類和處理語句有關(實際上Dialect是一個介面,抽象子類AbstractDialect的屬性LimitHandler才是實際sql的邏輯處理類,processSql是處理方法入口。為了方便理解,就以Dialect概括,一個Dialect對應一種資料來源的處理)
2.Dialect和databaseId有關
databaseId其實就是資料來源型別,Dialect是處理sql的類,每一種資料來源對應一個Dialect,通過databaseId獲取對應的Dialect然後進行sql加工處理,com.jn.sqlhelper.mybatis.plugins.pagination的PaginationHandler類beginIfSupportsLimit方法:
3.實際出問題的地方
其實就是databaseId的獲取,com.jn.sqlhelper.mybatis包下MybatisUtils類getDatabaseId方法:
紅框才是罪魁禍首(暫且先不看藍框),通過斷點除錯,發現獲取的是org.apache.ibatis.session.Configuration類的databaseId。那問題來了,Configuration類的databaseId是什麼時候設定的呢?通過Configuration的setDatabaseId方法的斷點除錯,發現該方法是專案啟動的時候才呼叫。org.mybatis.spring.SqlSessionFactoryBean類的buildSqlSessionFactory方法
這也解釋通了為什麼SQLHelper只按照某種資料來源來處理分頁語句。
4.為什麼按照primary指定的主資料來源處理?
一切從簡,上關鍵程式碼(接Configuration的setDatabaseId方法):
com.baomidou.dynamic.datasource.DynamicRoutingDataSource類的determineDataSource方法
com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder類的peek()方法返回當前執行緒/程式碼使用的資料來源名稱,啟動時沒有觸發push操作,所以返回為空。
空值則返回primary指定的預設資料庫,所以Configuration的databaseId是dynamic在配置檔案用primary指定的主資料來源:
5.DynamicDataSourceContextHolder的push:
dynamic會將當前執行緒使用的資料來源存入threadlocal裡
com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor.invoke方法,會將當前執行緒使用的資料來源名稱存入
這個push觸發的機制,應該是dynamic註解掃描到的地方。這也解釋了為什麼啟動的時候peek返回空,因為沒有觸發push操作。
三.解決方案:
既然知道問題所在,那麼就有解決思路了:MybatisUtils的getDatabaseId方法,返回正確的資料就行。
1.不走全域性獲取databaseId
如果能提前知道現在的資料來源是什麼,然後通過這個資料來源獲取databaseId就好了。巧的是DynamicDataSourceContextHolder類的peek()是一個靜態方法,並且入參MappedStatement ms可以獲取到dynamic配置的所有資料來源資訊:
2.通過connection獲取databaseId
其實就是二.3的藍框放前面就行,由於整合了連線池,所以不需要擔心查詢之前多連線一次資料庫。tx.getConnection()原始碼有興趣的也可以翻一下哦。
3.後續版本優化
四.小結
- SQLHelper根據databaseId(資料來源型別)處理分頁語句的類是LimitHandler;databaseId和LimitHandler、Dialect,是1:1:1的關係。
- springboot+tx.mybatis+dynamic+SQLHelper的技術選型下,SQLHelper在dynamic情況下分頁處理有問題。
- 處理方案經實踐,mybatis是完全可以適配的。不知道其他orm框架是否適用!
五.彩蛋時間
最近終於稍微脫離了CRDU的業務程式碼,開始往底層摸索了。框架需要適配dynamic,其實我也是什麼都不懂,沒辦法只能查資料看看dynamic是什麼,然後通過斷點除錯的方式探索開源框架的處理流程,說實話,最後發現問題並且解決問題的時候,還是有一點自豪感和成就感的!
框架這個版本的需求功能,需要用到的技術棧其實我基本沒聽過,但是有壓力就有動力,能讓自己多學一些總是好的!
另外附上和SQLHelper作者在github上的討論地址:此次論劍,略輸一籌(滑稽,HSPCode就是本萌新)
萌新發言,不喜勿噴,歡迎大佬指出不當之處!
相關文章
- Springboot整合mybatis實現多資料來源所遇到的問題Spring BootMyBatis
- Springboot通過AOP整合多資料來源,分析@Transaction切換資料來源不生效問題Spring Boot
- springboot整合分頁外掛pageHelper 返回全部資料問題Spring Boot
- weblogic多資料來源故障轉移問題Web
- SpirngBoot整合Mybatis Plus多資料來源bootMyBatis
- SpringBoot 整合多資料來源(MyBatis + Druid)Spring BootMyBatisUI
- MO_or掰泡饃式教學實現多資料來源
- springboot 多資料來源,最簡單的整合方式Spring Boot
- 苞米豆的多資料來源 → dynamic-datasource-spring-boot-starter,挺香的!Springboot
- 多工學習中的資料分佈問題(二)
- 多工學習中的資料分佈問題(一)
- springboot liquibase整合mysql與clickhouse多資料來源Spring BootUIMySql
- SpringBoot+Mybatis+ Druid+PageHelper 實現多資料來源並分頁Spring BootMyBatisUI
- ssm讀寫分離多資料來源SSM
- springboot 2 Hikari 多資料來源配置問題(dataSourceClassName or jdbcUrl is required)Spring BootJDBCUI
- 資料庫系列:巨量資料表的分頁效能問題資料庫
- 資料整合平臺,多種異構資料來源連結
- 如何向大牛請教問題?
- 當查詢的資料來自多個資料來源,有哪些好的分頁策略?
- Java中的多資料來源管理:如何在單個應用中整合多資料庫Java資料庫
- SpringBoot整合MyBatis-Plus實現多資料來源操作Spring BootMyBatis
- SpringBoot整合Druid資料來源Spring BootUI
- MyBatis整合雙資料來源MyBatis
- 多資料來源與動態資料來源的權衡
- Spring-Boot 多資料來源配置+動態資料來源切換+多資料來源事物配置實現主從資料庫儲存分離Springboot資料庫
- mybatis多資料來源踩坑,資料庫連線經常斷開問題MyBatis資料庫
- MySQL order by limit 分頁資料重複問題MySqlMIT
- 什麼是報表的多樣性資料來源問題?如何解決?
- 多資料來源配置
- SpringBoot多資料來源Spring Boot
- sbt配置——資料來源問題解決
- SpringBoot 的多資料來源配置Spring Boot
- SpringBoot2 整合JTA元件,多資料來源事務管理Spring Boot元件
- 重寫 API 資源分頁資料API
- 同學,你的多資料來源事務失效了
- springboot+mybatisplus+druid資料來源:SQLException問題Spring BootMyBatisUISQLException
- Spring多資料來源配置Spring
- springBoot 多資料來源配置Spring Boot