详解使用spring aop实现业务层mysql 读写分离
发布时间 - 2026-01-10 22:20:35 点击率:次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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# spring
# mysql读写分离
# aop
# 读写分离
# Spring AOP切面解决数据库读写分离实例详解
# SpringMVC4+MyBatis+SQL Server2014实现数据库读写分离
# SpringBoot集成Spring Data JPA及读写分离
# 详解Spring AOP 实现主从读写分离
# Spring+MyBatis实现数据库读写分离方案
# Spring配置动态数据源实现读写分离的方法
# Spring boot实现数据库读写分离的方法
# Spring 实现数据库读写分离的示例
# 使用Spring AOP实现MySQL数据库读写分离案例分析(附demo)
# Spring动态数据源实现读写分离详解
# 自己的
# 都是
# 是从
# 这两个
# 可以通过
# 还需要
# 配置文件
# 将把
# 大家多多
# 自动更新
# 主要是
# 同步更新
# 下次
# target
# service
# pointCut
# point
# getSignature
# method
# Class
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
昵图网官方站入口 昵图网素材图库官网入口
Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
Laravel用户密码怎么加密_Laravel Hash门面使用教程
黑客如何通过漏洞一步步攻陷网站服务器?
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
想要更高端的建设网站,这些原则一定要坚持!
手机网站制作与建设方案,手机网站如何建设?
Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤
香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧
如何用PHP快速搭建高效网站?分步指南
佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】
Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制
如何快速搭建虚拟主机网站?新手必看指南
湖南网站制作公司,湖南上善若水科技有限公司做什么的?
如何做网站制作流程,*游戏网站怎么搭建?
C#如何调用原生C++ COM对象详解
linux写shell需要注意的问题(必看)
如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框
如何快速上传建站程序避免常见错误?
Laravel如何实现多对多模型关联?(Eloquent教程)
Laravel路由怎么定义_Laravel核心路由系统完全入门指南
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
用yum安装MySQLdb模块的步骤方法
如何彻底删除建站之星生成的Banner?
JavaScript如何操作视频_媒体API怎么控制播放
如何在IIS7上新建站点并设置安全权限?
在线制作视频的网站有哪些,电脑如何制作视频短片?
如何挑选最适合建站的高性能VPS主机?
Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区
jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?
大连 网站制作,大连天途有线官网?
如何在万网利用已有域名快速建站?
如何在Windows环境下新建FTP站点并设置权限?
如何在云指建站中生成FTP站点?
Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】
深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
Python正则表达式进阶教程_复杂匹配与分组替换解析
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
Laravel定时任务怎么设置_Laravel Crontab调度器配置
Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程
html文件怎么打开证书错误_https协议的html打开提示不安全【指南】
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
Python结构化数据采集_字段抽取解析【教程】
*服务器网站为何频现安全漏洞?

