spring读写分离(mysql主从复制<3>)

一.读写分离原理:

 上一篇文章我们已经讲解了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下载地址

最后谢谢大家,大家觉得我写的可以 可以给我鼓励 打赏一下,多少都可以 哈哈哈




猜你喜欢

转载自blog.csdn.net/zzxwx/article/details/78045380