Spring读写分离技术

转载 2016年08月28日 16:20:29
在应用层通过spring特性解决数据库读写分离

如何配置mysql数据库的主从?
单机配置mysql主从:http://my.oschina.net/god/blog/496
 
常见的解决数据库读写分离有两种方案
1、应用层
http://neoremind.net/2011/06/spring实现数据库读写分离
目前的一些解决方案需要在程序中手动指定数据源,比较麻烦,后边我会通过AOP思想来解决这个问题。
 
2、中间件
mysql-proxy:http://hi.baidu.com/geshuai2008/item/0ded5389c685645f850fab07
Amoeba for MySQL:http://www.iteye.com/topic/188598http://www.iteye.com/topic/1113437
 
此处我们介绍一种在应用层的解决方案,通过spring动态数据源和AOP来解决数据库的读写分离。
 
该方案目前已经在一个互联网项目中使用了,而且可以很好的工作。
 
该方案目前支持
一读多写;当写时默认读操作到写库、当写时强制读操作到读库。
 
考虑未来支持
读库负载均衡、读库故障转移等。
 
使用场景
不想引入中间件,想在应用层解决读写分离,可以考虑这个方案;
建议数据访问层使用jdbc、ibatis,不建议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">  
  1.     <property name="alias" value="writeDataSource"/>  
  1.     <property name="driver" value="${write.connection.driver_class}" />  
  1.     <property name="driverUrl" value="${write.connection.url}" />  
  1.     <property name="user" value="${write.connection.username}" />  
  1.     <property name="password" value="${write.connection.password}" />  
  1.     <property name="maximumConnectionCount" value="${write.proxool.maximum.connection.count}"/>  
  1.     <property name="minimumConnectionCount" value="${write.proxool.minimum.connection.count}" />  
  1.     <property name="statistics" value="${write.proxool.statistics}" />  
  1.     <property name="simultaneousBuildThrottle" value="${write.proxool.simultaneous.build.throttle}"/>  
  1. </bean>  
 
1.2、读库配置
Java代码  收藏代码
  1. <bean id="readDataSource1" class="org.logicalcobwebs.proxool.ProxoolDataSource">  
  1.     <property name="alias" value="readDataSource"/>  
  1.     <property name="driver" value="${read.connection.driver_class}" />  
  1.     <property name="driverUrl" value="${read.connection.url}" />  
  1.     <property name="user" value="${read.connection.username}" />  
  1.     <property name="password" value="${read.connection.password}" />  
  1.     <property name="maximumConnectionCount" value="${read.proxool.maximum.connection.count}"/>  
  1.     <property name="minimumConnectionCount" value="${read.proxool.minimum.connection.count}" />  
  1.     <property name="statistics" value="${read.proxool.statistics}" />  
  1.     <property name="simultaneousBuildThrottle" value="${read.proxool.simultaneous.build.throttle}"/>  
  1. </bean>   
1.3、读写动态库配置   
通过writeDataSource指定写库,通过readDataSourceMap指定从库列表,从库列表默认通过顺序轮询来使用读库,具体参考javadoc;
Java代码  收藏代码
  1. <bean id="readWriteDataSource" class="cn.javass.common.datasource.ReadWriteDataSource">  
  1.     <property name="writeDataSource" ref="writeDataSource"/>  
  1.     <property name="readDataSourceMap">  
  1.        <map>  
  1.           <entry key="readDataSource1" value-ref="readDataSource1"/>  
  1.           <entry key="readDataSource2" value-ref="readDataSource1"/>  
  1.           <entry key="readDataSource3" value-ref="readDataSource1"/>  
  1.           <entry key="readDataSource4" value-ref="readDataSource1"/>  
  1.        </map>  
  1.     </property>  
  1. </bean>   
 
2、XML事务属性配置
所以读方法必须是read-only(必须,以此来判断是否是读方法)。
Java代码  收藏代码
  1. <tx:advice id="txAdvice" transaction-manager="txManager">  
  1.     <tx:attributes>  
  1.         <tx:method name="save*" propagation="REQUIRED" />  
  1.         <tx:method name="add*" propagation="REQUIRED" />  
  1.         <tx:method name="create*" propagation="REQUIRED" />  
  1.         <tx:method name="insert*" propagation="REQUIRED" />  
  1.         <tx:method name="update*" propagation="REQUIRED" />  
  1.         <tx:method name="merge*" propagation="REQUIRED" />  
  1.         <tx:method name="del*" propagation="REQUIRED" />  
  1.         <tx:method name="remove*" propagation="REQUIRED" />  
  1.           
  1.         <tx:method name="put*" read-only="true"/>  
  1.         <tx:method name="query*" read-only="true"/>  
  1.         <tx:method name="use*" read-only="true"/>  
  1.         <tx:method name="get*" read-only="true" />  
  1.         <tx:method name="count*" read-only="true" />  
  1.         <tx:method name="find*" read-only="true" />  
  1.         <tx:method name="list*" read-only="true" />  
  1.           
  1.         <tx:method name="*" propagation="REQUIRED"/>  
  1.     </tx:attributes>  
  1. </tx:advice>   
 
3、事务管理器
事务管理器管理的是readWriteDataSource
Java代码  收藏代码
  1. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  1.         <property name="dataSource" ref="readWriteDataSource"/>  
  1.     </bean>   
 
4、读/写动态数据库选择处理器
根据之前的txAdvice配置的事务属性决定是读/写,具体参考javadoc;
forceChoiceReadWhenWrite:用于确定在如果目前是写(即开启了事务),下一步如果是读,是直接参与到写库进行读,还是强制从读库读,具体参考javadoc;
Java代码  收藏代码
  1. <bean id="readWriteDataSourceTransactionProcessor" class="cn.javass.common.datasource.ReadWriteDataSourceProcessor">  
  1.    <property name="forceChoiceReadWhenWrite" value="false"/>  
  1. </bean>   
 
5、事务切面和读/写库选择切面
Java代码  收藏代码
  1. <aop:config expose-proxy="true">  
  1.     <!-- 只对业务逻辑层实施事务 -->  
  1.     <aop:pointcut id="txPointcut" expression="execution(* cn.javass..service..*.*(..))" />  
  1.     <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>  
  1.       
  1.     <!-- 通过AOP切面实现读/写库选择 -->  
  1.     <aop:aspect order="-2147483648" ref="readWriteDataSourceTransactionProcessor">  
  1.        <aop:around pointcut-ref="txPointcut" method="determineReadOrWriteDB"/>  
  1.     </aop:aspect>  
  1. </aop:config>   
1、事务切面一般横切业务逻辑层;
2、此处我们使用readWriteDataSourceTransactionProcessor的通过AOP切面实现读/写库选择功能,order=Integer.MIN_VALUE(即最高的优先级),从而保证在操作事务之前已经决定了使用读/写库。
 
6、测试用例
只要配置好事务属性(通过read-only=true指定读方法)即可,其他选择读/写库的操作都交给readWriteDataSourceTransactionProcessor完成。
 
可以参考附件的:
cn.javass.readwrite.ReadWriteDBTestWithForceChoiceReadOnWriteFalse
cn.javass.readwrite.ReadWriteDBTestWithNoForceChoiceReadOnWriteTrue
 

mysql+spring+mybatis实现数据库读写分离[代码配置]

mysql+spring+mybatis实现数据库读写分离[代码配置]
  • xtj332
  • xtj332
  • 2015年02月26日 16:50
  • 37045

Spring和MyBatis实现数据的读写分离

1.Spring实现数据库的读写分离 现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询,S...
  • he90227
  • he90227
  • 2016年04月26日 10:07
  • 10453

spring MVC、mybatis配置读写分离

1.环境:    3台数据库机器,一个master,二台slave,分别为slave1,slave2      2.要实现的目标:    ①使数据写入到master    ②读数据时,从slave1和...
  • lixiucheng005
  • lixiucheng005
  • 2013年12月18日 11:34
  • 18682

Spring+Mybatis透明实现读写分离

背景网上有好多读写分离的实践,所应对的业务场景也不一样,本方法主要是应对中小型互联网产品的读写分离。数据库环境:1台master;2台slaver适用框架:spring+mybatis操作数据库的简单...
  • johnstrive
  • johnstrive
  • 2016年09月20日 16:58
  • 1489

MySQL主从复制技术与读写分离技术amoeba应用

目前在搭建大型网站,需要用到分布式数据库技术,MySQL的主从复制+读写分离技术。读写分离技术有官方的MySQL-proxy,阿里巴巴的Amoeba。Amoeba能在阿里巴巴这么大流量的平台投入使用而...
  • ljuncong
  • ljuncong
  • 2014年08月29日 15:02
  • 7286

spring jpa 读写分离

本文主要解决基于spring data jpa读写分离。 思想:在dataSource做路由,根据事务判断使用主从数据源。 背景:spring+spring data jpa(hibern...
  • hangge111
  • hangge111
  • 2016年06月07日 17:53
  • 2156

spring读写分离 - 事务注解篇

思路参照 spring读写分离 - 事务配置篇(转) ,不过是基于@Transactional判断,所以每个需要事务的方法上都必须添加上这个注解,这里直接贴出代码: 配置文件: 多数据源配置: ...
  • linminqin
  • linminqin
  • 2015年10月12日 22:14
  • 3913

Spring+MyBatis实现数据库读写分离方案

推荐第四种 方案1 通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactoryBean对象的mapperLocations属性制定两个读写数据源的配...
  • xwnxwn
  • xwnxwn
  • 2016年12月27日 11:16
  • 1808

使用spring aop实现业务层mysql 读写分离

spring aop , mysql 主从配置 实现读写分离,下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。 mysql主从配置参看:http://blog....
  • huoyunshen88
  • huoyunshen88
  • 2014年07月03日 17:35
  • 14412

Spring和MyBatis实现数据的读写分离

1.Spring实现数据库的读写分离 现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询...
  • xyw591238
  • xyw591238
  • 2016年04月28日 14:09
  • 2231
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spring读写分离技术
举报原因:
原因补充:

(最多只允许输入30个字)