使用Spring AOP实现MySQL读写分离
spring aop , mysql 主从配置 实现读写分离,下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。
mysql主从配置参看:http://blog.csdn.net/huoyunshen88/article/details/26597483
1.使用spring aop 拦截机制现数据源的动态选取。
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface DataSource {
- String value();
- }
3.利用Spring的AbstractRoutingDataSource解决多数据源的问题 参考本站《使用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);
- }
测试读操作:
后台修改从库数据,查看主库的数据没有被修改,在应用页面中刷新,发现读的是从库的数据,说明读写分离ok。
http://www.sunyaozong.com/mysql-read-write-sepreate-solution-by-spring-aop/
使用Spring AOP实现MySQL读写分离的更多相关文章
- Spring AOP 实现数据库读写分离
背景 我们一般应用对数据库而言都是"读多写少",也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案, 其中一个是主库,负责写入数据,我们称之为:写库: 其它都 ...
- 从零开始学 Java - Spring AOP 实现主从读写分离
深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...
- Spring Boot+MyBatis+MySQL读写分离
读写分离要做的事情就是对于一条sql语句该选择去哪个数据库执行,至于谁来做选择数据库的事情,无非两个,1:中间件(比如MyCat):二:程序自己去做分离操作. 但是从程序成眠去做读写分离最大的弱点就是 ...
- 170301、使用Spring AOP实现MySQL数据库读写分离案例分析
使用Spring AOP实现MySQL数据库读写分离案例分析 原创 2016-12-29 徐刘根 Java后端技术 一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案 ...
- spring集成mybatis实现mysql读写分离
前言 在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈.幸运的是目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库的数据更新同步到另一台服务器上. ...
- 使用Spring实现MySQL读写分离(转)
使用Spring实现MySQL读写分离 为什么要进行读写分离 大量的JavaWeb应用做的是IO密集型任务, 数据库的压力较大, 需要分流 大量的应用场景, 是读多写少, 数据库读取的压力更大 一个很 ...
- Spring配置动态数据源-读写分离和多数据源
在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...
- Spring AOP实现Mysql数据库主从切换(一主多从)
设置数据库主从切换的原因:数据库中经常发生的是“读多写少”,这样读操作对数据库压力比较大,通过采用数据库集群方案, 一个数据库是主库,负责写:其他为从库,负责读,从而实现读写分离增大数据库的容错率. ...
- 提高性能,MySQL 读写分离环境搭建
这是松哥之前一个零散的笔记,整理出来分享给大伙! MySQL 读写分离在互联网项目中应该算是一个非常常见的需求了.受困于 Linux 和 MySQL 版本问题,很多人经常会搭建失败,今天松哥就给大伙举 ...
随机推荐
- Theorems for existence and uniqueness of variational problem
Introduction Among simulation engineers, it is well accepted that the solution of a PDE can be envis ...
- [转]安卓手机google商店的账号切换退出方式
来源:http://blog.csdn.net/bianchengninhao/article/details/42240839 1.设置 2.账户 3.Google 4. 5.点击菜单键 6.最后删 ...
- word/excel/cad中插入二维码
1.有需求为在word文档中插入二维码,寻访度娘后,大部分人推荐使用QRmaker制作. 2.找寻QRmaker,网上很多都是1.1版本,后来才知道这个版本有问题(对中文支持不好),偶然得到1.3的版 ...
- IIS 无法显示网页 目前访问网站的用户过多
最近把一个服务部署到XP系统的IIS上,供其他程序调用,在访问了几个页面后,会出现“无法显示网页 目前访问网站的用户过多”的提示. 网上找了,果然有解决方法: 1.打开IIS,在网站上右键,选择“属性 ...
- Codeforces 765F Souvenirs 线段树 + 主席树 (看题解)
Souvenirs 我们将询问离线, 我们从左往右加元素, 如果当前的位置为 i ,用一棵线段树保存区间[x, i]的答案, 每次更新完, 遍历R位于 i 的询问更新答案. 我们先考虑最暴力的做法, ...
- 今天才知道原来我还没弄清楚js中全局变量和局部变量的定义...
查资料看到这段还不错,来源:原文:https://blog.csdn.net/czh500/article/details/80429133 粘过来记录一下... 1.使用var声明变量,在方法内部是 ...
- linux系统虚拟机下安装jdk
首先需要得到可以创建文件和上传文件的权限 . 将下载好的jdk文件上传到指定的文件目录下. tar -zxvf jdk-8u60-linux-x64.tar.gz 解压到当前文件下 会 ...
- 20165235 祁瑛 2018-3 《Java程序设计》第四周学习总结
20165235 祁瑛 2018-3 <Java程序设计>第四周学习总结 教材学习内容总结 第五单云总结 (一)子类与继承1.java中子类只能有一个父类,在类名前用extends标记.2 ...
- Spring(四)使用注解注入Bean
注解简单介绍 是代码里面的特殊标记,使用注解完成功能. 注解写法@ 注解名称(属性名=属性值). 注解可以作用在类.方法.属性上面. 使用流程: 在ApplicationContext.xml中开启注 ...
- 初窥Java之五
一.方法 1.语法格式 修饰符 返回值类型 方法名(形参列表){ 方法体 } 2.返回值类型 返回值类型可以时:1.void(无返回值) 2.8大基本数据类型中的任意一种 3.引用数据类型中的任意一 ...