`

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

    博客分类:
  • Java
 
阅读更多

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

1.使用spring aop 拦截机制现数据源的动态选取。

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. import java.lang.annotation.ElementType;  
  2. import java.lang.annotation.Target;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. /**  
  6.  * RUNTIME  
  7.  * 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。  
  8.  * @author yangGuang  
  9.  *  
  10.  */  
  11. @Retention(RetentionPolicy.RUNTIME)  
  12. @Target(ElementType.METHOD)  
  13. public @interface DataSource {  
  14.     String value();  
  15. }  


 
 3.利用Spring的AbstractRoutingDataSource解决多数据源的问题 参考: http://blog.csdn.net/alaahong/article/details/8707915

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  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.        
  10.  }  



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

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  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注解。

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  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

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  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.使用注解,动态选择数据源,分别走读库和写库。

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  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。

 
遇到的问题总结:

  问题1:项目是maven工程,用到了Spring aop机制,除了spring的核心jar包以为,还需要用到的jar包有aspectj.jar,aspectjweaver.jar,aopalliance.jar查看项目中的pom,发现缺少依赖包,
    由于本地仓库没有这些jar,查找可以提供下载jar包的maven中央库库,配置到maven中,自动更新:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <repository>  
  2.      <id>nexus</id>  
  3.      <name>nexus</name>  
  4.      <url>http://repository.sonatype.org/content/groups/public/</url>  
  5.      <layout>default</layout>  
  6.  </repository>  


    配置项目依赖的jar,主要是缺少这两个。

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1.    <dependency>  
  2.        <groupId>aspectj</groupId>  
  3.        <artifactId>aspectjrt</artifactId>  
  4.        <version>1.5.4</version>  
  5. </dependency>  
  6. <dependency>  
  7.        <groupId>aspectj</groupId>  
  8.        <artifactId>aspectjweaver</artifactId>  
  9.        <version>1.5.4</version>  
  10. lt;/dependency>  
分享到:
评论

相关推荐

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

    本文将详细解析如何使用Spring AOP来实现业务层的MySQL读写分离。首先,我们需要理解Spring AOP(面向切面编程)的基本概念,它允许我们在不修改原有代码的情况下,通过切面(Aspect)插入额外的功能,比如日志、...

    springaop多数据库读写分离

    在IT行业中,数据库读写分离是一种常见的优化策略,主要用于提高系统的并发处理能力和数据读取...在实际项目中,还可以考虑使用中间件如MySQL的Proxy或商业化解决方案如MaxScale来实现更高级的读写分离和负载均衡策略。

    AOP动态实现MYSQL数据库读写分离

    本示例通过Java的面向切面编程(AOP)技术来实现实现MySQL数据库的读写分离,旨在帮助开发者理解如何在实际项目中应用这一技术。 首先,我们要理解什么是AOP(Aspect-Oriented Programming)。AOP是面向切面编程的...

    spring之mysql读写分离

    本文将深入探讨如何利用Spring AOP(面向切面编程)实现应用层的MySQL读写分离,并结合一主多从的配置来进行详细讲解。 首先,我们需要理解MySQL的主从复制机制。在主从复制中,数据的写操作(INSERT、UPDATE、...

    spring mysql 读写分离

    Spring与MySQL读写分离** Spring作为一个灵活的Java应用程序框架,提供了多种方式来支持数据库的读写分离。通过配置数据源、事务管理器以及AOP(面向切面编程)等机制,Spring可以帮助我们透明地处理读写操作的路由...

    springboot实现mysql的读写分离的案例源码

    读写分离就是对于一条SQL该选择哪一个数据库去执行,至于谁来做选择数据库这件事,有两个,要么使用中间件帮我们做,要么程序自己做。一般来说,读写分离有两种实现方式。第一种是依靠中间件MyCat,也就是说应用程序...

    使用Spring实现读写分离(MySQL实现主从复制)

    在Spring框架下实现读写分离的核心在于通过AOP(面向切面编程)技术,在调用业务逻辑方法前根据一定的规则(如方法名前缀)来决定使用哪个数据源。具体实现包括以下几个步骤: 1. **定义动态数据源**:继承`...

    实现mysql读写分离+使用视频

    “使用Spring实现读写分离(MySQL实现主从复制).docx”文档可能会提供更详尽的文字说明和代码示例,帮助你更好地理解视频中的内容,并在自己的项目中实现这一技术。 至于“mysql.zip”,“sql”和“mysql资料”...

    springBoot+mybatis读写分离(AOP)

    通过以上步骤,我们成功地在Spring Boot项目中实现了基于AOP的读写分离。这种方式不需要额外的插件,代码简洁,易于理解和维护。在高并发场景下,这种方案能够有效地减轻数据库压力,提高系统响应速度,是优化数据库...

    Spring+mysql读写分离

    本示例"Spring+MySQL+MyBatis+SpringMVC 读写分离"是针对这种策略的一个实现,旨在帮助开发者理解如何在实际项目中应用这一技术。下面将详细介绍这个Demo中的关键知识点。 首先,我们要理解什么是读写分离。读写...

    spring aop 读写分离

    最后,为了实现读写分离,你需要在服务层或者DAO层的接口和实现类中使用上述注解。例如: ```java public interface UserService { @ReadOnly User getUserById(Long id); @Transactional void updateUser...

    springboot 实现mysql读写分离 通过aop 并且根据方法名进行分类 实现读写分离

    在现代企业级应用开发中,数据的高可用性和性能优化是至关重要的。Spring Boot作为Java领域最流行的微服务框架...不过,以上步骤为你提供了一个基础的读写分离实现框架,你可以在此基础上根据项目需求进行扩展和调整。

    使用springboot aop来实现读写分离和事物配置

    三、使用Spring AOP来实现读写分离 实现读写分离的步骤可以分为以下几步: 1、创建一个Maven项目,导入SpringBoot依赖。 2、添加依赖项,包括SpringBoot Starter Web、SpringBoot Starter AOP、MyBatis Spring ...

    JAVA数据库读写分离项目源码(MYSQL)

    本项目源码是基于MySQL数据库实现的,利用SSM(Spring、SpringMVC、MyBatis)框架进行开发,旨在帮助开发者快速理解和实践读写分离技术。 首先,我们来理解一下“读写分离”的概念。读写分离是指在分布式数据库系统...

    Spring AOP 实现读写分离(MySQL实现主从复制)-附件资源

    Spring AOP 实现读写分离(MySQL实现主从复制)-附件资源

    Spring实现数据库读写分离

    下面将详细讲解如何利用Spring MVC、Spring和MyBatis来实现数据库的读写分离。 1. **Spring MVC**:Spring MVC是Spring框架的一部分,主要负责处理Web应用中的请求和响应。它提供了模型-视图-控制器(MVC)架构模式...

    spring +springboot+mybatis+maven 读写分离及事务管理

    spring +springboot+mybatis+maven 读写分离,数据库采用mysql, 采用springboot 采用项目框架搭建,继承spring 中的AbstractRoutingDataSource,实现 determineCurrentLookupKey 进行数据源的动态切换,采用Spring ...

    Spring配置Mysql读写分离[定义].pdf

    Spring配置MySQL读写分离是一种常见的优化策略,用于提高数据库系统的性能和可扩展性。在大型分布式系统中,读写分离可以有效地将高并发的读操作与写操作分摊到不同的数据库服务器上,从而减轻主数据库的压力,确保...

Global site tag (gtag.js) - Google Analytics