spring aop , mysql 主从配置 实现读写分离,接下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。
1.使用spring aop 拦截机制现数据源的动态选取。
import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * RUNTIME * 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 * @author yangGuang * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSource { String value(); }
3.利用Spring的AbstractRoutingDataSource解决多数据源的问题
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class ChooseDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return HandleDataSource.getDataSource(); } }
4.利用ThreadLocal解决线程安全问题
public class HandleDataSource { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void putDataSource(String datasource) { holder.set(datasource); } public static String getDataSource() { return holder.get(); } }
5.定义一个数据源切面类,通过aop访问,在spring配置文件中配置了,所以没有使用aop注解。
import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; //@Aspect //@Component public class DataSourceAspect { //@Pointcut("execution(* com.apc.cms.service.*.*(..))") public void pointCut(){}; // @Before(value = "pointCut()") public void before(JoinPoint point) { Object target = point.getTarget(); System.out.println(target.toString()); String method = point.getSignature().getName(); System.out.println(method); Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz[0].getMethod(method, parameterTypes); System.out.println(m.getName()); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m.getAnnotation(DataSource.class); HandleDataSource.putDataSource(data.value()); } } catch (Exception e) { e.printStackTrace(); } } }
6.配置applicationContext.xml
<!-- 主库数据源 --> <bean id="writeDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://172.22.14.6:3306/cpp?autoReconnect=true"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="partitionCount" value="4"/> <property name="releaseHelperThreads" value="3"/> <property name="acquireIncrement" value="2"/> <property name="maxConnectionsPerPartition" value="40"/> <property name="minConnectionsPerPartition" value="20"/> <property name="idleMaxAgeInSeconds" value="60"/> <property name="idleConnectionTestPeriodInSeconds" value="60"/> <property name="poolAvailabilityThreshold" value="5"/> </bean> <!-- 从库数据源 --> <bean id="readDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://172.22.14.7:3306/cpp?autoReconnect=true"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="partitionCount" value="4"/> <property name="releaseHelperThreads" value="3"/> <property name="acquireIncrement" value="2"/> <property name="maxConnectionsPerPartition" value="40"/> <property name="minConnectionsPerPartition" value="20"/> <property name="idleMaxAgeInSeconds" value="60"/> <property name="idleConnectionTestPeriodInSeconds" value="60"/> <property name="poolAvailabilityThreshold" value="5"/> </bean> <!-- transaction manager, 事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 注解自动载入 --> <context:annotation-config /> <!--enale component scanning (beware that this does not enable mapper scanning!)--> <context:component-scan base-package="com.apc.cms.persistence.rdbms" /> <context:component-scan base-package="com.apc.cms.service"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> </context:component-scan> <context:component-scan base-package="com.apc.cms.auth" /> <!-- enable transaction demarcation with annotations --> <tx:annotation-driven /> <!-- define the SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="typeAliasesPackage" value="com.apc.cms.model.domain" /> </bean> <!-- scan for mappers and let them be autowired --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.apc.cms.persistence" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> <bean id="dataSource" class="com.apc.cms.utils.ChooseDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <!-- write --> <entry key="write" value-ref="writeDataSource"/> <!-- read --> <entry key="read" value-ref="readDataSource"/> </map> </property> <property name="defaultTargetDataSource" ref="writeDataSource"/> </bean> <!-- 激活自动代理功能 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 配置数据库注解aop --> <bean id="dataSourceAspect" class="com.apc.cms.utils.DataSourceAspect" /> <aop:config> <aop:aspect id="c" ref="dataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.apc.cms.service..*.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> </aop:aspect> </aop:config> <!-- 配置数据库注解aop -->
7.使用注解,动态选择数据源,分别走读库和写库。
@DataSource("write") public void update(User user) { userMapper.update(user); } @DataSource("read") public Document getDocById(long id) { return documentMapper.getById(id); }
测试写操作:可以通过应用修改数据,修改主库数据,发现从库的数据被同步更新了,所以定义的write操作都是走的写库
测试读操作: 后台修改从库数据,查看主库的数据没有被修改,在应用页面中刷新,发现读的是从库的数据,说明读写分离ok。
遇到的问题总结:
问题1:项目是maven工程,用到了Spring aop机制,除了spring的核心jar包以为,还需要用到的jar包有aspectj.jar,aspectjweaver.jar,aopalliance.jar查看项目中的pom,发现缺少依赖包,由于本地仓库没有这些jar,查找可以提供下载jar包的maven中央库库,配置到maven中,自动更新:
<repository> <id>nexus</id> <name>nexus</name> <url>http://repository.sonatype.org/content/groups/public/</url> <layout>default</layout> </repository>
配置项目依赖的jar,主要是缺少这两个。
<dependency> <groupId>aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.5.4</version> </dependency> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.4</version> lt;/dependency>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍MySQL 读写分离实例详解,包括了MySQL 读写分离实例详解的使用技巧和注意事项,需要的朋友参考一下 MySQL 读写分离 MySQL读写分离又一好办法 使用 com.mysql.jdbc.ReplicationDriver 在用过Amoeba 和 Cobar,还有dbware 等读写分离组件后,今天我的一个好朋友跟我讲,MySQL自身的也是可以读写分离的,因为他们提供了一个新的
本文向大家介绍详解Spring AOP 实现主从读写分离,包括了详解Spring AOP 实现主从读写分离的使用技巧和注意事项,需要的朋友参考一下 深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的。「读写分离」并不是多么神奇的东西,也带不来多么大的性能提升
本文向大家介绍详解如何利用amoeba(变形虫)实现mysql数据库读写分离,包括了详解如何利用amoeba(变形虫)实现mysql数据库读写分离的使用技巧和注意事项,需要的朋友参考一下 关于mysql的读写分离架构有很多,百度的话几乎都是用mysql_proxy实现的。由于proxy是基于lua脚本语言实现的,所以网上不少网友表示proxy效率不高,也不稳定,不建议在生产环境使用; amoeba
本文向大家介绍Mybatis注解实现多数据源读写分离详解,包括了Mybatis注解实现多数据源读写分离详解的使用技巧和注意事项,需要的朋友参考一下 首先需要建立两个库进行测试,我这里使用的是master_test和slave_test两个库,两张库都有一张同样的表(偷懒,喜喜),表结构 表名 t_user | 字段名 | 类型 | 备注 | | :------: | :------: | :---
本文向大家介绍springboot基于Mybatis mysql实现读写分离,包括了springboot基于Mybatis mysql实现读写分离的使用技巧和注意事项,需要的朋友参考一下 近日工作任务较轻,有空学习学习技术,遂来研究如果实现读写分离。这里用博客记录下过程,一方面可备日后查看,同时也能分享给大家(网上的资料真的大都是抄来抄去,,还不带格式的,看的真心难受)。 完整代码:https:/
本文向大家介绍PHP实现的mysql读写分离操作示例,包括了PHP实现的mysql读写分离操作示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP实现的mysql读写分离操作。分享给大家供大家参考,具体如下: 首先mysql主从需配置好,基本原理就是判断sql语句是否是select,是的话走master库,否则从slave查 结果: I am using master db.. 19