天天看點

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

  采用讀寫分離技術的目标:有效減輕master庫的壓力,又可以把使用者查詢資料的請求分發到不同的slave庫,進而保證系統的健壯性。我們看下采用讀寫分離的背景。

  随着網站的業務不斷擴充,資料不斷增加,使用者越來越多,資料庫的壓力也就越來越大,采用傳統的方式,比如:資料庫或者sql的優化基本已達不到要求,這個時候可以采用讀寫分離的策 略來改變現狀。

  具體到開發中,如何友善的實作讀寫分離呢?目前常用的有兩種方式:

  1 第一種方式是我們最常用的方式,就是定義2個資料庫連接配接,一個是masterdatasource,另一個是slavedatasource。更新資料時我們讀取masterdatasource,查詢資料時我們讀取slavedatasource。這種方式很簡單,我就不贅述了。

,反射。下面會詳細的介紹實作方式。

   在介紹實作方式之前,我們先準備一些必要的知識,spring 的abstractroutingdatasource 類

     abstractroutingdatasource這個類 是spring2.0以後增加的,我們先來看下abstractroutingdatasource的定義:

    public abstract class abstractroutingdatasource extends abstractdatasource implements initializingbean  {}

    abstractroutingdatasource繼承了abstractdatasource ,而abstractdatasource 又是datasource

的子類。datasource   是javax.sql 的資料源接口,定義如下:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

  datasource 接口定義了2個方法,都是擷取資料庫連接配接。我們在看下abstractroutingdatasource 如何實作了datasource接口:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

  很顯然就是調用自己的determinetargetdatasource()  方法擷取到connection。determinetargetdatasource方法定義如下:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

   我們最關心的還是下面2句話:

    object lookupkey = determinecurrentlookupkey();

        datasource datasource = this.resolveddatasources.get(lookupkey);

    determinecurrentlookupkey方法傳回lookupkey,resolveddatasources方法就是根據lookupkey從map中獲得資料源。resolveddatasources 和determinecurrentlookupkey定義如下:

  private map<object, datasource> resolveddatasources;

  protected abstract object determinecurrentlookupkey()

  看到以上定義,我們是不是有點思路了,resolveddatasources是map類型,我們可以把masterdatasource和slavedatasource存到map中,如下:

    key        value

    master             masterdatasource

    slave                  slavedatasource

  我們在寫一個類dynamicdatasource  繼承abstractroutingdatasource,實作其determinecurrentlookupkey() 方法,該方法傳回map的key,master或slave。

  好了,說了這麼多,有點煩了,下面我們看下怎麼實作。

   上面已經提到了我們要使用的技術,我們先看下annotation的定義:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

    我們還需要實作spring的抽象類abstractroutingdatasource,就是實作determinecurrentlookupkey方法:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

    從dynamicdatasource 的定義看出,他傳回的是dynamicdatasourceholder.getdatasouce()值,我們需要在程式運作時調用dynamicdatasourceholder.putdatasource()方法,對其指派。下面是我們實作的核心部分,也就是aop部分,datasourceaspect定義如下:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

    為了友善測試,我定義了2個資料庫,shop模拟master庫,test模拟slave庫,shop和test的表結構一緻,但資料不同,資料庫配置如下:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

  在spring的配置中增加aop配置

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

   下面是mybatis的usermapper的定義,為了友善測試,登入讀取的是master庫,使用者清單讀取slave庫:

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

   好了,運作我們的eclipse看看效果,輸入使用者名admin 登入看看效果

  

spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離
spring 實作資料庫讀寫分離 1.Spring實作資料庫的讀寫分離 2.MyBatis多資料源配置 實作讀寫分離

  從圖中可以看出,登入的使用者和使用者清單的資料是不同的,也驗證了我們的實作,登入讀取master庫,使用者清單讀取slave庫。

首先說明,本文的配置使用的最直接的方式,實際用起來可能會很麻煩。

實際應用中可能存在多種結合的情況,你可以了解本文的含義,不要死闆的使用。

針對這種情況,一個更好的解決方法可以參考(本人沒有實際嘗試過):

<a target="_blank" href="http://blog.csdn.net/lixiucheng005/article/details/17391857">http://blog.csdn.net/lixiucheng005/article/details/17391857</a>

還有一個通過spring<code>abstractroutingdatasource</code>路由接口的方式:

<a target="_blank" href="http://blog.csdn.net/xtj332/article/details/43953699">http://blog.csdn.net/xtj332/article/details/43953699</a>

這種情況可以參考本文,但是需要注意每一個資料庫對應的mapper要在不同的包下友善區分和配置。

另外分庫的情況下也會存在主從的情況,如果你的資料庫從庫過多,就參考上面提供的方法,或者尋找其他方式解決。

分庫的情況下,不同的資料庫的mapper一定放在不同的包下。

主從的情況下,同一個mapper會同時存在讀寫的情況,建立兩個并不合适,使用同一個即可。但是這種情況下需要注意,spring對mapper自動生成的名字是相同的,而且類型也相同,這是就不能直接注入<code>mapper</code>接口。需要通過<code>sqlsession</code>來解決。

這個檔案,主要是引入了<code>spring-datasource-master.xml</code>和<code>spring-datasource-slave.xml</code>。

和<code>master</code>差別不大,主要是<code>id</code>名字和資料源配置有差別。

這裡需要注意<code>&lt;tx:method name="*" read-only="true"/&gt;</code>是隻讀的。如果不是從庫,可以按主庫進行配置。

在下面代碼中:

必須通過<code>sqlsessionfactorybeanname</code>來指定不同的<code>sqlsessionfactory</code>。

這裡是針對主從的情況進行設定的,兩個配置掃描的<code>mapper</code>是一樣的,是以沒法直接注入,需要通過下面的麻煩方式注入。

因為<code>sqlsession</code>能通過<code>name</code>區分開,是以這裡從<code>sqlsession</code>擷取<code>mapper</code>。

另外如果需要考慮在同一個事務中寫讀的時候,需要使用相同的<code>writemapper</code>,這樣在讀的時候,才能擷取事務中的最新資料。

以上是主從的情況。

在分庫的情況時,由于不同mapper在不同的包下,是以可以直接使用<code>@resource</code>或者<code>@autowired</code>注入<code>mapper</code>,不需要通過<code>sqlsession</code>擷取。