spring讀寫分離(mysql主從複製)

一.讀寫分離原理:

 上一篇文章我們已經講解了mysql主從複製的原理並且實現了   只要往主服務器中插入數據  那麼從數據庫slaver將會跟着同步主服務器master的數據

 那麼我們java 代碼來實現的話  只要動態切換數據庫 就達到了讀寫分離的目的。本文中是用spring + mybatis 來整合案例的  那麼我們如果能夠做到動態
 的切換spring的數據源 從而就可以達到切換數據庫的目的

二.spring實現切換數據庫原理:


     通過Spring的AOP思想來實現   根據你訪問的service方法名來判斷此方法執行查詢還是執行更改操作
     一般查詢切換到從數據源    更改插入刪除操作在主數據庫   因爲主數據庫會同步到從數據庫
    

     此時我們spring-mybatis.xml 文件中至少應該有兩個數據源 masterDataSource  和slaverDataSource  稍後貼出 
     masterDataSource數據源配置 和我們普通的配置沒什麼差別(數據庫信息從配置文件讀取)
    
     <!-- 主庫 用來寫數據 -->
<bean id="dataSourceWriter" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 初始化連接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 連接池最大數量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 連接池最大空閒 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 連接池最小空閒 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 獲取連接最大等待時間 -->
<property name="maxWait" value="${maxWait}"></property>
</bean>

     slaverDataSource  數據源 
      <!-- 從庫用來讀數據 -->
<bean id="dataSourceReader" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${slaver.driver}" />
<property name="url" value="${slaver.url}" />
<property name="username" value="${slaver.username}" />
<property name="password" value="${slaver.password}" />
<!-- 初始化連接大小 -->
<property name="initialSize" value="${slaver.initialSize}"></property>
<!-- 連接池最大數量 -->
<property name="maxActive" value="${slaver.maxActive}"></property>
<!-- 連接池最大空閒 -->
<property name="maxIdle" value="${slaver.maxIdle}"></property>
<!-- 連接池最小空閒 -->
<property name="minIdle" value="${slaver.minIdle}"></property>
<!-- 獲取連接最大等待時間 -->
<property name="maxWait" value="${slaver.maxWait}"></property>
</bean>
     我們原來sqlSessionFactory的bean中的屬性dataSource 應該指向我們包含主數據源和從數據源的bean
     
     所以我們要定義一個dynamicDataSource 來管理masterDatas 和slaverDataSource   代碼如下
     
   <!-- 動態數據源 -->  
   <bean id="dynamicDataSource" class="com.cn.wx.db.DynamicDataSource">  
       <!-- 通過key-value關聯數據源 -->  
       <property name="targetDataSources">  
           <map>  
               <entry value-ref="dataSourceWriter" key="dataSourceWriter"></entry>  
               <entry value-ref="dataSourceReader" key="dataSourceReader"></entry>  
           </map>  
       </property>
       <!-- 默認的DataSource配置-->
       <property name="defaultTargetDataSource" ref="dataSourceWriter" />      
   </bean>

    此bean的class是我們自定義的class  需要集成 spring中的 AbstractRoutingDataSource重寫一下方法
    
     @Override
protected Object determineCurrentLookupKey() {
// TODO Auto-generated method stub
return DBContextHolder.getDbType();
}  

DBContextHolder 類是我們自己定義的  用來返回與當前線程綁定的數據源的名稱
核心代碼如下:
/** 
* 線程threadlocal 
*/  
    private static ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
  
    private static String DEFAUL_DB_TYPE_WRITER = "dataSourceWriter";   
    
    /* 獲取本線程的dbtype
    * @return
    */
   public static String getDbType() {  
       String db = contextHolder.get();  
       if (db == null) {  
           db = DEFAUL_DB_TYPE_WRITER;// 默認是讀寫庫  
       }  
       return db;  
   
 


3. spring AOP配置實現數據源切換:   

 我們訪問以 select*  get* find* query* 開頭的Service方法都會切換到讀的數據源    直接上代碼
   
  <!-- 數據源讀寫分離  aop -->
    <bean id="dynamicDataSourceAOP" class="com.cn.wx.db.DynamicDataSourceAOP">
        <property name="methods"> 
             <map>                  
                 <entry key="select*" value="dataSourceReader" />
                 <entry key="get*" value="dataSourceReader" />
                 <entry key="find*" value="dataSourceReader" />
                 <entry key="page*" value="dataSourceReader" />            
                 <entry key="query*" value="dataSourceReader" />
             </map>
           </property>
        <property name="defaultDataSource" value="dataSourceWriter"/>
     </bean>
      
     DynamicDataSourceAOP 是我們自己來根據service方法不同來切換數據源的核心邏輯 如下:

      

spring-mybatis.xml 中在原來的aop:config中加入AOP的切面如下:

至此其實我們的配置已經完畢 接下來就是測試讀寫分離是否成功。

4.測試讀寫分離配置是否成功:

接下我們來測試是否成功的實現了讀寫分離

我們插入往主數據庫中插入一條數據    這個時候去查看從數據庫 是否也有這條記錄  有的話說明成功!

 

         繼續驗證讀  是否從從數據庫中讀取的 代碼如下:

,注意查詢方法是AOP中攔截到的  數據源纔會去切換到slaverDataSource  

此時主從數據庫一樣怎麼驗證查詢的是從數據庫呢   很簡單 我們手動去修改從數據庫的某一個字段值 除了按條件查詢的值以外 都可以

此時我們主數據庫數據如下:



從數據庫數據如下:


修改從數據庫的age 爲28 此時主數據庫還是原來的25 

如果查詢的結果是28那麼讀寫分離就已經實現了

現在執行查詢方法

     sql語句打印的age是28  到此爲止 就已經實現了讀寫分離

     demo下載地址

最後謝謝大家,大家覺得我寫的可以 可以給我鼓勵 打賞一下,多少都可以 哈哈哈




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章