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. 005 Numpy的基本操作

    一:数组与标量,数组与数组之间的运算 1.数组与标量之间的计算 2.数组之间的加减乘除 3.元素级运算 二:.矩阵积 1.说明 这个的意思是第一个数组的列,必须和第二个数组的行的大小相同 2.运算 3 ...

  2. Harmonic Number(调和级数+欧拉常数)

    In mathematics, the nth harmonic number is the sum of the reciprocals of the first n natural numbers ...

  3. TF之RNN:TensorBoard可视化之基于顺序的RNN回归案例实现蓝色正弦虚线预测红色余弦实线—Jason niu

    import tensorflow as tf import numpy as np import matplotlib.pyplot as plt BATCH_START = 0 TIME_STEP ...

  4. 2601 电路维修 (双端队列bfs\优先队列bfs(最短路))

    描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板 ...

  5. Codeforces 1105D Kilani and the Game【BFS】

    <题目链接> 题目大意: 每个玩家控制一个颜色去扩张,每个颜色的扩张有自己的速度,一个颜色跑完再跑下一种颜色.在所有颜色不能在继续扩张的时候停止游戏.询问此时各种颜色的数量. 解题分析: ...

  6. POJ 2455 Secret Milking Machine 【二分】+【最大流】

    <题目链接> 题目大意: FJ有N块地,这些地之间有P条双向路,每条路的都有固定的长度l.现在要你找出从第1块地到第n块地的T条不同路径,每条路径上的路段不能与先前的路径重复,问这些路径中 ...

  7. 深度学习(TensorFlow)环境搭建:(三)Ubuntu16.04+CUDA8.0+cuDNN7+Anaconda4.4+Python3.6+TensorFlow1.3

    紧接着上一篇的文章<深度学习(TensorFlow)环境搭建:(二)Ubuntu16.04+1080Ti显卡驱动>,这篇文章,主要讲解如何安装CUDA+CUDNN,不过前提是我们是已经把N ...

  8. 解决UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range

    字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(en ...

  9. vue项目的搭建使用

    环境变量的安装 参考  环境变量详解 第一次搭建参考 参考  简单初始项目搭建 配置好环境变量的项目的搭建 新建一个new proproject, 查看工作目录vue是否存在    使用查看指令  v ...

  10. JavaScript基础笔记(三) 引用类型

    引用类型 引用类型的值(对象)是引用类型的一个实例. 一.Object类型 创建Object实例: //方法一:通过new操作符创建 var a = new Object(); a.neme = &q ...