zoukankan      html  css  js  c++  java
  • 解决数据库读写分离(转)

    如何配置mysql数据库的主从?

    单机配置mysql主从:http://my.oschina.net/god/blog/496

     

    常见的解决数据库读写分离有两种方案

    1、应用层

    http://neoremind.net/2011/06/spring实现数据库读写分离

    目前的一些解决方案需要在程序中手动指定数据源,比较麻烦,后边我会通过AOP思想来解决这个问题。

     

    2、中间件

    mysql-proxyhttp://hi.baidu.com/geshuai2008/item/0ded5389c685645f850fab07

    Amoeba for MySQLhttp://www.iteye.com/topic/188598http://www.iteye.com/topic/1113437

     

    此处我们介绍一种在应用层的解决方案,通过spring动态数据源和AOP来解决数据库的读写分离。

     

    该方案目前已经在一个互联网项目中使用了,而且可以很好的工作。

     

    该方案目前支持

    一读多写;当写时默认读操作到写库、当写时强制读操作到读库。

     

    考虑未来支持

    读库负载均衡、读库故障转移等。

     

    使用场景

    不想引入中间件,想在应用层解决读写分离,可以考虑这个方案;

    建议数据访问层使用jdbcibatis,不建议hibernate。

     

    优势

    应用层解决,不引入额外中间件;

    在应用层支持『当写时默认读操作到写库』,这样如果我们采用这种方案,在写操作后读数据直接从写库拿,不会产生数据复制的延迟问题;

    应用层解决读写分离,理论支持任意数据库。

     

     

    缺点

    1、不支持@Transactional注解事务,此方案要求所有读方法必须是read-only=true,因此如果是@Transactional,这样就要求在每一个读方法头上加@Transactional 且readOnly属性=true,相当麻烦。 :oops: 

    2、必须按照配置约定进行配置,不够灵活。

     

    两种方案



    方案1:当只有读操作的时候,直接操作读库(从库);

            当在写事务(即写主库)中读时,也是读主库(即参与到主库操作),这样的优势是可以防止写完后可能读不到刚才写的数据;

     

    此方案其实是使用事务传播行为为:SUPPORTS解决的。

     


    方案2:当只有读操作的时候,直接操作读库(从库);

            当在写事务(即写主库)中读时,强制走从库,即先暂停写事务,开启读(读从库),然后恢复写事务。

    此方案其实是使用事务传播行为为:NOT_SUPPORTS解决的。

     

    核心组件

    cn.javass.common.datasource.ReadWriteDataSource:读写分离的动态数据源,类似于AbstractRoutingDataSource,具体参考javadoc

    cn.javass.common.datasource.ReadWriteDataSourceDecision:读写库选择的决策者,具体参考javadoc

    cn.javass.common.datasource.ReadWriteDataSourceProcessor:此类实现了两个职责(为了减少类的数量将两个功能合并到一起了):读/写动态数据库选择处理器、通过AOP切面实现读/写选择,具体参考javadoc

     

    具体配置

    1、数据源配置

    1.1、写库配置

    Java代码  收藏代码
    1.     <bean id="writeDataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">  
    2.     <property name="alias" value="writeDataSource"/>  
    3.     <property name="driver" value="${write.connection.driver_class}" />  
    4.     <property name="driverUrl" value="${write.connection.url}" />  
    5.     <property name="user" value="${write.connection.username}" />  
    6.     <property name="password" value="${write.connection.password}" />  
    7.     <property name="maximumConnectionCount" value="${write.proxool.maximum.connection.count}"/>  
    8.     <property name="minimumConnectionCount" value="${write.proxool.minimum.connection.count}" />  
    9.     <property name="statistics" value="${write.proxool.statistics}" />  
    10.     <property name="simultaneousBuildThrottle" value="${write.proxool.simultaneous.build.throttle}"/>  
    11. </bean>  

     

    1.2、读库配置

    Java代码  收藏代码
    1. <bean id="readDataSource1" class="org.logicalcobwebs.proxool.ProxoolDataSource">  
    2.     <property name="alias" value="readDataSource"/>  
    3.     <property name="driver" value="${read.connection.driver_class}" />  
    4.     <property name="driverUrl" value="${read.connection.url}" />  
    5.     <property name="user" value="${read.connection.username}" />  
    6.     <property name="password" value="${read.connection.password}" />  
    7.     <property name="maximumConnectionCount" value="${read.proxool.maximum.connection.count}"/>  
    8.     <property name="minimumConnectionCount" value="${read.proxool.minimum.connection.count}" />  
    9.     <property name="statistics" value="${read.proxool.statistics}" />  
    10.     <property name="simultaneousBuildThrottle" value="${read.proxool.simultaneous.build.throttle}"/>  
    11. </bean>   

    1.3、读写动态库配置   

    通过writeDataSource指定写库,通过readDataSourceMap指定从库列表,从库列表默认通过顺序轮询来使用读库,具体参考javadoc

    Java代码  收藏代码
    1. <bean id="readWriteDataSource" class="cn.javass.common.datasource.ReadWriteDataSource">  
    2.     <property name="writeDataSource" ref="writeDataSource"/>  
    3.     <property name="readDataSourceMap">  
    4.        <map>  
    5.           <entry key="readDataSource1" value-ref="readDataSource1"/>  
    6.           <entry key="readDataSource2" value-ref="readDataSource1"/>  
    7.           <entry key="readDataSource3" value-ref="readDataSource1"/>  
    8.           <entry key="readDataSource4" value-ref="readDataSource1"/>  
    9.        </map>  
    10.     </property>  
    11. </bean>   

     

    2XML事务属性配置

    所以读方法必须是read-only(必须,以此来判断是否是读方法)。

    Java代码  收藏代码
    1. <tx:advice id="txAdvice" transaction-manager="txManager">  
    2.     <tx:attributes>  
    3.         <tx:method name="save*" propagation="REQUIRED" />  
    4.         <tx:method name="add*" propagation="REQUIRED" />  
    5.         <tx:method name="create*" propagation="REQUIRED" />  
    6.         <tx:method name="insert*" propagation="REQUIRED" />  
    7.         <tx:method name="update*" propagation="REQUIRED" />  
    8.         <tx:method name="merge*" propagation="REQUIRED" />  
    9.         <tx:method name="del*" propagation="REQUIRED" />  
    10.         <tx:method name="remove*" propagation="REQUIRED" />  
    11.           
    12.         <tx:method name="put*" read-only="true"/>  
    13.         <tx:method name="query*" read-only="true"/>  
    14.         <tx:method name="use*" read-only="true"/>  
    15.         <tx:method name="get*" read-only="true" />  
    16.         <tx:method name="count*" read-only="true" />  
    17.         <tx:method name="find*" read-only="true" />  
    18.         <tx:method name="list*" read-only="true" />  
    19.           
    20.         <tx:method name="*" propagation="REQUIRED"/>  
    21.     </tx:attributes>  
    22. </tx:advice>   
  • 相关阅读:
    Kbuild文件
    patch与diff的恩怨
    依据linux Oops信息准确定位错误代码所在行
    理解嵌入式开发中的一些硬件相关的概念
    linux内核中经常用到的设备初始化宏
    如何实例化i2c_client(四法)
    设计和编写设备驱动的一般方法
    [转] rtp h264注意点(FU-A分包方式说明)
    c语言的label后面不能直接跟变量申明
    互联网目前最有影响力的流量统计网站
  • 原文地址:https://www.cnblogs.com/jpfss/p/8109496.html
Copyright © 2011-2022 走看看