zoukankan      html  css  js  c++  java
  • 使用Spring AOP实现MySQL读写分离

    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.  
    3. public class ChooseDataSource extends AbstractRoutingDataSource {
    4.  
    5. @Override
    6. protected Object determineCurrentLookupKey() {
    7. return HandleDataSource.getDataSource();
    8. }
    9. }

    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.  
    7. public static String getDataSource() {
    8. return holder.get();
    9. }
    10. }

    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.  
    14. // @Before(value = "pointCut()")
    15. public void before(JoinPoint point)
    16. {
    17. Object target = point.getTarget();
    18. System.out.println(target.toString());
    19. String method = point.getSignature().getName();
    20. System.out.println(method);
    21. Class<?>[] classz = target.getClass().getInterfaces();
    22. Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
    23. .getMethod().getParameterTypes();
    24. try {
    25. Method m = classz[0].getMethod(method, parameterTypes);
    26. System.out.println(m.getName());
    27. if (m != null && m.isAnnotationPresent(DataSource.class)) {
    28. DataSource data = m.getAnnotation(DataSource.class);
    29. HandleDataSource.putDataSource(data.value());
    30. }
    31.  
    32. } catch (Exception e) {
    33. e.printStackTrace();
    34. }
    35. }
    36. }

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

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

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


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

  • 相关阅读:
    centos7 nfs安装
    Rasa在PyCharm中进行debug
    IOS的? !
    IOS中IndexPath
    移动端文本框点击后网页变大的解决办法
    h5 在全屏iphonex中的适配
    net5中得logging保存到文件中
    SQL SERVER 2000数据库置疑处理
    ILSpy源码下载后,编译不过的问题
    Tigase8.x 搭配Mysql8及以上启动时报错(Nodes redirection table: tig_cluster_nodes doesn't exits)的解决方法
  • 原文地址:https://www.cnblogs.com/langtianya/p/7631806.html
Copyright © 2011-2022 走看看