springboot讀寫分離--temp


我最初的想法是: 讀方法走讀庫,寫方法走寫庫(一般是主庫),保證在Spring提交事務之前確定數據源.

保證在Spring提交事務之前確定數據源,這個簡單,利用AOP寫個切換數據源的切面,讓他的優先級高於Spring事務切面的優先級。至於讀,寫方法的區分可以用2個注解。

但是如何切換數據庫呢? 我完全不知道!多年經驗告訴我

我搜索了一些網文,發現都提到了一個AbstractRoutingDataSource類。查看源碼注釋如下

/**

Abstract {@link javax.sql.DataSource} implementation that routes {@link #getConnection()}

* calls to one of various target DataSources based on a lookup key. The latter is usually

* (but not necessarily) determined through some thread-bound transaction context.

*

* @author Juergen Hoeller

* @since 2.0.1

* @see #setTargetDataSources

* @see #setDefaultTargetDataSource

* @see #determineCurrentLookupKey()

*/

AbstractRoutingDataSource就是DataSource的抽象,基於lookup key的方式在多個數據庫中進行切換。重點關注setTargetDataSources,setDefaultTargetDataSource,determineCurrentLookupKey三個方法。那么AbstractRoutingDataSource就是Spring讀寫分離的關鍵了。

仔細閱讀了三個方法,基本上跟方法名的意思一致。setTargetDataSources設置備選的數據源集合。 setDefaultTargetDataSource設置默認數據源,determineCurrentLookupKey決定當前數據源的對應的key。

但是我很好奇這3個方法都沒有包含切換數據庫的邏輯啊!我仔細閱讀源碼發現一個方法,determineTargetDataSource方法,其實它才是獲取數據源的實現。源碼如下:

簡單說就是,根據determineCurrentLookupKey獲取的key,在resolvedDataSources這個Map中查找對應的datasource!,注意determineTargetDataSource方法竟然不使用的targetDataSources!

那一定存在resolvedDataSources與targetDataSources的對應關系。我接着翻閱代碼,發現一個afterPropertiesSet方法(Spring源碼中InitializingBean接口中的方法),這個方法將targetDataSources的值賦予了resolvedDataSources。源碼如下:

afterPropertiesSet 方法,熟悉Spring的都知道,它在bean實例已經創建好,且屬性值和依賴的其他bean實例都已經注入以后執行。

也就是說調用,targetDataSources,defaultTargetDataSource的賦值一定要在afterPropertiesSet前邊執行。

AbstractRoutingDataSource簡單總結:

  1. AbstractRoutingDataSource,內部有一個Map<Object,DataSource>的域resolvedDataSources

  2. determineTargetDataSource方法通過determineCurrentLookupKey方法獲得key,進而從map中取得對應的DataSource。

  3. setTargetDataSources 設置 targetDataSources

  4. setDefaultTargetDataSource 設置 defaultTargetDataSource,

  5. targetDataSources和defaultTargetDataSource 在afterPropertiesSet分別轉換為resolvedDataSources和resolvedDefaultDataSource。

  6. targetDataSources,defaultTargetDataSource的賦值一定要在afterPropertiesSet前邊執行。

進一步了解理論后,讀寫分離的方式則基本上出現在眼前了。(“下列方法不唯一”)

先寫一個類繼承AbstractRoutingDataSource,實現determineCurrentLookupKey方法,和afterPropertiesSet方法。afterPropertiesSet方法中調用setDefaultTargetDataSource和setTargetDataSources方法之后調用super.afterPropertiesSet。

之后定義一個切面在事務切面之前執行,確定真實數據源對應的key。但是這又出現了一個問題,如何線程安全的情況下傳遞每個線程獨立的key呢?沒錯使用ThreadLocal傳遞真實數據源對應的key。

ThreadLocal,Thread的局部變量,確保每一個線程都維護變量的一個副本

到這里基本邏輯就想通了,之后就是寫了。

DataSourceContextHolder 使用ThreadLocal存儲真實數據源對應的key

DataSourceAopAspect 切面切換真實數據源對應的key,並設置優先級保證高於事務切面

RoutingDataSouceImpl實現AbstractRoutingDataSource的邏輯

基本邏輯實現完畢了就進行,通用設置,設置數據源,事務,SqlSessionFactory等

其他代碼,就不在這里贅述了,有興趣可以移步完整代碼。

使用Spring寫讀寫分離,其核心就是AbstractRoutingDataSource,源碼不難,讀懂之后,寫個讀寫分離就簡單了!。

AbstractRoutingDataSource重點回顧:

  1. AbstractRoutingDataSource,內部有一個Map<Object,DataSource>的域resolvedDataSources

  2. determineTargetDataSource方法通過determineCurrentLookupKey方法獲得key,進而從map中取得對應的DataSource。

  3. setTargetDataSources 設置 targetDataSources

  4. setDefaultTargetDataSource 設置 defaultTargetDataSource,

  5. targetDataSources和defaultTargetDataSource 在afterPropertiesSet分別轉換為resolvedDataSources和resolvedDefaultDataSource。

  6. targetDataSources,defaultTargetDataSource的賦值一定要在afterPropertiesSet前邊執行。

這周確實有點忙,周五花費了些時間不過總算實現了自己的諾言。

完成承諾不容易,喜歡您就點個贊!


免責聲明!

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



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