spring aop , mysql 主从配置 实现读写分离,下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。
mysql主从配置参看:http://blog.csdn.net/huoyunshen88/article/details/26597483
1.使用spring aop 拦截机制现数据源的动态选取。

 
  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.METHOD)
  3. public @interface DataSource {
  4. String value();
  5. }

3.利用Spring的AbstractRoutingDataSource解决多数据源的问题 参考本站《使用Spring的AbstractRoutingDataSource解决多数据源的问题》

 
  1. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  2. public class ChooseDataSource extends AbstractRoutingDataSource {
  3. @Override
  4. protected Object determineCurrentLookupKey() {
  5. return HandleDataSource.getDataSource();
  6. }
  7. }

4.利用ThreadLocal解决线程安全问题

 
  1. public class HandleDataSource {
  2. public static final ThreadLocal<String> holder = new ThreadLocal<String>();
  3. public static void putDataSource(String datasource) {
  4. holder.set(datasource);
  5. }
  6. public static String getDataSource() {
  7. return holder.get();
  8. }
  9. }

5.定义一个数据源切面类,通过aop访问,在spring配置文件中配置了,所以没有使用aop注解

 
  1. import java.lang.reflect.Method;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.annotation.Aspect;
  4. import org.aspectj.lang.annotation.Before;
  5. import org.aspectj.lang.annotation.Pointcut;
  6. import org.aspectj.lang.reflect.MethodSignature;
  7. import org.springframework.stereotype.Component;
  8. //@Aspect
  9. //@Component
  10. public class DataSourceAspect {
  11. //@Pointcut("execution(* com.apc.cms.service.*.*(..))")
  12. public void pointCut(){};
  13. // @Before(value = "pointCut()")
  14. public void before(JoinPoint point)
  15. {
  16. Object target = point.getTarget();
  17. System.out.println(target.toString());
  18. String method = point.getSignature().getName();
  19. System.out.println(method);
  20. Class<?>[] classz = target.getClass().getInterfaces();
  21. Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
  22. .getMethod().getParameterTypes();
  23. try {
  24. Method m = classz[0].getMethod(method, parameterTypes);
  25. System.out.println(m.getName());
  26. if (m != null && m.isAnnotationPresent(DataSource.class)) {
  27. DataSource data = m.getAnnotation(DataSource.class);
  28. HandleDataSource.putDataSource(data.value());
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }

6.配置applicationContext.xml

 
  1. <!-- 主库数据源 -->
  2. <bean id="writeDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
  3. <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  4. <property name="jdbcUrl" value="jdbc:mysql://172.22.14.6:3306/cpp?autoReconnect=true"/>
  5. <property name="username" value="root"/>
  6. <property name="password" value="root"/>
  7. <property name="partitionCount" value="4"/>
  8. <property name="releaseHelperThreads" value="3"/>
  9. <property name="acquireIncrement" value="2"/>
  10. <property name="maxConnectionsPerPartition" value="40"/>
  11. <property name="minConnectionsPerPartition" value="20"/>
  12. <property name="idleMaxAgeInSeconds" value="60"/>
  13. <property name="idleConnectionTestPeriodInSeconds" value="60"/>
  14. <property name="poolAvailabilityThreshold" value="5"/>
  15. </bean>
  16. <!-- 从库数据源 -->
  17. <bean id="readDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
  18. <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  19. <property name="jdbcUrl" value="jdbc:mysql://172.22.14.7:3306/cpp?autoReconnect=true"/>
  20. <property name="username" value="root"/>
  21. <property name="password" value="root"/>
  22. <property name="partitionCount" value="4"/>
  23. <property name="releaseHelperThreads" value="3"/>
  24. <property name="acquireIncrement" value="2"/>
  25. <property name="maxConnectionsPerPartition" value="40"/>
  26. <property name="minConnectionsPerPartition" value="20"/>
  27. <property name="idleMaxAgeInSeconds" value="60"/>
  28. <property name="idleConnectionTestPeriodInSeconds" value="60"/>
  29. <property name="poolAvailabilityThreshold" value="5"/>
  30. </bean>
  31. <!-- transaction manager, 事务管理 -->
  32. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  33. <property name="dataSource" ref="dataSource" />
  34. </bean>
  35. <!-- 注解自动载入 -->
  36. <context:annotation-config />
  37. <!--enale component scanning (beware that this does not enable mapper scanning!)-->
  38. <context:component-scan base-package="com.apc.cms.persistence.rdbms" />
  39. <context:component-scan base-package="com.apc.cms.service">
  40. <context:include-filter type="annotation"
  41. expression="org.springframework.stereotype.Component" />
  42. </context:component-scan>
  43. <context:component-scan base-package="com.apc.cms.auth" />
  44. <!-- enable transaction demarcation with annotations -->
  45. <tx:annotation-driven />
  46. <!-- define the SqlSessionFactory -->
  47. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  48. <property name="dataSource" ref="dataSource" />
  49. <property name="typeAliasesPackage" value="com.apc.cms.model.domain" />
  50. </bean>
  51. <!-- scan for mappers and let them be autowired -->
  52. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  53. <property name="basePackage" value="com.apc.cms.persistence" />
  54. <property name="sqlSessionFactory" ref="sqlSessionFactory" />
  55. </bean>
  56. <bean id="dataSource" class="com.apc.cms.utils.ChooseDataSource">
  57. <property name="targetDataSources">
  58. <map key-type="java.lang.String">
  59. <!-- write -->
  60. <entry key="write" value-ref="writeDataSource"/>
  61. <!-- read -->
  62. <entry key="read" value-ref="readDataSource"/>
  63. </map>
  64. </property>
  65. <property name="defaultTargetDataSource" ref="writeDataSource"/>
  66. </bean>
  67. <!-- 激活自动代理功能 -->
  68. <aop:aspectj-autoproxy proxy-target-class="true"/>
  69. <!-- 配置数据库注解aop -->
  70. <bean id="dataSourceAspect" class="com.apc.cms.utils.DataSourceAspect" />
  71. <aop:config>
  72. <aop:aspect id="c" ref="dataSourceAspect">
  73. <aop:pointcut id="tx" expression="execution(* com.apc.cms.service..*.*(..))"/>
  74. <aop:before pointcut-ref="tx" method="before"/>
  75. </aop:aspect>
  76. </aop:config>
  77. <!-- 配置数据库注解aop -->

7.使用注解,动态选择数据源,分别走读库和写库

 
  1. @DataSource("write")
  2. public void update(User user) {
  3. userMapper.update(user);
  4. }
  5. @DataSource("read")
  6. public Document getDocById(long id) {
  7. return documentMapper.getById(id);
  8. }
测试写操作:可以通过应用修改数据,修改主库数据,发现从库的数据被同步更新了,所以定义的write操作都是走的写库
测试读操作:
后台修改从库数据,查看主库的数据没有被修改,在应用页面中刷新,发现读的是从库的数据,说明读写分离ok。

http://www.sunyaozong.com/mysql-read-write-sepreate-solution-by-spring-aop/

使用Spring AOP实现MySQL读写分离的更多相关文章

  1. Spring AOP 实现数据库读写分离

    背景 我们一般应用对数据库而言都是"读多写少",也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案, 其中一个是主库,负责写入数据,我们称之为:写库: 其它都 ...

  2. 从零开始学 Java - Spring AOP 实现主从读写分离

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  3. Spring Boot+MyBatis+MySQL读写分离

    读写分离要做的事情就是对于一条sql语句该选择去哪个数据库执行,至于谁来做选择数据库的事情,无非两个,1:中间件(比如MyCat):二:程序自己去做分离操作. 但是从程序成眠去做读写分离最大的弱点就是 ...

  4. 170301、使用Spring AOP实现MySQL数据库读写分离案例分析

    使用Spring AOP实现MySQL数据库读写分离案例分析 原创 2016-12-29 徐刘根 Java后端技术 一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案 ...

  5. spring集成mybatis实现mysql读写分离

    前言 在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈.幸运的是目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库的数据更新同步到另一台服务器上. ...

  6. 使用Spring实现MySQL读写分离(转)

    使用Spring实现MySQL读写分离 为什么要进行读写分离 大量的JavaWeb应用做的是IO密集型任务, 数据库的压力较大, 需要分流 大量的应用场景, 是读多写少, 数据库读取的压力更大 一个很 ...

  7. Spring配置动态数据源-读写分离和多数据源

    在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...

  8. Spring AOP实现Mysql数据库主从切换(一主多从)

    设置数据库主从切换的原因:数据库中经常发生的是“读多写少”,这样读操作对数据库压力比较大,通过采用数据库集群方案, 一个数据库是主库,负责写:其他为从库,负责读,从而实现读写分离增大数据库的容错率.  ...

  9. 提高性能,MySQL 读写分离环境搭建

    这是松哥之前一个零散的笔记,整理出来分享给大伙! MySQL 读写分离在互联网项目中应该算是一个非常常见的需求了.受困于 Linux 和 MySQL 版本问题,很多人经常会搭建失败,今天松哥就给大伙举 ...

随机推荐

  1. wb 黑名单批量操作

    0. 参考 yu961549745/WeiboBlackList  微博批量拉黑 1. 代码 block.py 更新内容:多线程,urllib.request 改为 requests + sessio ...

  2. python之requests urllib3 连接池

    0.目录 1.参考 2. pool_connections 默认值为10,一个站点主机host对应一个pool (4)分析 host A>>host B>>host A pag ...

  3. asp.net Web API 身份验证 不记名令牌验证 Bearer Token Authentication 简单实现

    1. Startup.Auth.cs文件 添加属性 1 public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; ...

  4. Python_函数_参数

    def   是函数的关键字,Python解释器一旦执行到def,默认不执行 def li(): n = 8 n +=1 print(n) li() li2 = li li2() 结果: 9 9 ret ...

  5. Fiddler教程--简介

    1.开发环境host配置 自己修改系统的host来回挺麻烦的 2.前后的接口调试 3.线上bugfix 4.性能分析和优化 5.等等... 工作原理 一个代理服务器 地址改为 127.0.0.1:88 ...

  6. PHP中使用CURL实现GET和POST请求(转载)

    CURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP.FTP.TELNET等.最爽的是,PHP也支持 CURL 库.使用PHP的CURL 库可以简单和有效地去抓网页.你只 ...

  7. P1052 过河 线性dp

    题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数 ...

  8. HBase API操作

    |的ascII最大ctrl+shift+t查找类  ctrl+p显示提示 HBase API操作 依赖的jar包 <dependencies> <dependency> < ...

  9. PMS及APP安装过程

    --摘自<android插件化开发指南> 1.PackageManagerService(PMS)是用来获取apk包的信息的 2.AMS总是会使用PMS加载包的信息,将其封装在Loaded ...

  10. hdu3944

    hdu3944题目中给出的杨辉三角形的形状带有误导目的,应该转化成对称的形状再去思考这个问题分两种情况第一个是在左区从目标位置向左上方走一直走到边界,然后再向右上方一直走到起点n-k个1加上C(n-k ...