Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作
发布时间 - 2026-01-11 03:13:28 点击率:次在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。

废话不多说,多数据源配置和主从数据配置原理一样
1、首先配置 jdbc.properties 两个数据库 A 和 B
#============ 双数据源 ======# #----------------------A servers--------------------------# A.driver=com.mysql.jdbc.Driver A.url=jdbc:mysql://localhost:3619/gps4?useUnicode=true&characterEncoding=utf8 A.username=gpsadmin A.password=1qaz&619 #----------------------B servers--------------------------# B.driver=com.mysql.jdbc.Driver B.url=jdbc:mysql://localhost:3619/gps6?useUnicode=true&characterEncoding=utf8 B.username=gpsadmin B.password=1qaz&619
2、配置 spring-mybatis.xml 文件【重要】
<!-- 引入配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:resources/jdbc.properties" />
</bean>
<!-- DBCP连接池 -->
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"> <property name="driverClassName" value="${driver}"
/> <property name="url" value="${url}" /> <property name="username" value="${username}"
/> <property name="password" value="${password}" /> 初始化连接大小 <property name="initialSize"
value="${initialSize}"></property> 连接池最大数量 <property name="maxActive" value="${maxActive}"></property>
连接池最大空闲 <property name="maxIdle" value="${maxIdle}"></property> 连接池最小空闲 <property
name="minIdle" value="${minIdle}"></property> 获取连接最大等待时间 <property name="maxWait"
value="${maxWait}"></property> </``> -->
<!-- 【重点】 A 数据源 -->
<bean name="dataSourceA" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${A.driver}" />
<property name="url" value="${A.url}" />
<property name="username" value="${A.username}" />
<property name="password" value="${A.password}" />
</bean>
<!-- 【重点】 B 数据源 -->
<bean name="dataSourceB" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${B.driver}" />
<property name="url" value="${B.url}" />
<property name="username" value="${B.username}" />
<property name="password" value="${B.password}" />
</bean>
<!--【重点】 双数据源 配合 -->
<bean id="dataSource" class="com.ifengSearch.common.database.DynamicDataSource">
<property name="defaultTargetDataSource" ref="dataSourceB"/>
<property name="targetDataSources">
<map>
<entry key="dataSourceA" value-ref="dataSourceA"/>
<entry key="dataSourceB" value-ref="dataSourceB"/>
</map>
</property>
</bean>
<!-- 【重点】 加入 aop 自动扫描 DataSourceAspect 配置数据库注解aop -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="manyDataSourceAspect" class="com.ifengSearch.common.database.DataSourceAspect" />
<aop:config>
<!-- 扫描 注解的 数据源 -->
<aop:aspect id="c" ref="manyDataSourceAspect">
<aop:pointcut id="tx" expression="execution(* com.ifengSearch.*.dao.*.*(..))"/>
<aop:before pointcut-ref="tx" method="before"/>
</aop:aspect>
</aop:config>
<!-- 配置数据连接 工厂 自动扫描mapping.xml文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/ifengSearch/*/mapping/*.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ifengSearch.*.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx 事务 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
3、编写几个java类动态调用数据源【重要】
a:自定义一个注解,负责动态调用数据源
package com.ifengSearch.common.database;
import java.lang.annotation.*;
/**
* 设置 数据源 注解标签的用法 写上注解标签,
* 调用相应方法切换数据源咯(就跟你设置事务一样)
* 【也可以配置 主从数据库】
*
* @author flm
* @2017年9月12日
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
public static String dataSourceA = "dataSourceA"; // A数据源
public static String dataSourceB = "dataSourceB"; // B数据源
String value();
}
b、数据源的获取 Object aop实现 (反射)
package com.ifengSearch.common.database;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
/**
* 数据源的获取
* aop实现 (反射)
* @author flm
* @2017年9月12日
*/
public class DataSourceAspect{
private Logger log = Logger.getLogger(DataSourceAspect.class);
public void before(JoinPoint point)
{
Object target = point.getTarget();// 拦截的实体类
String method = point.getSignature().getName();// 拦截的方法名称
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
.getMethod().getParameterTypes();// 拦截的方法参数类型
try {
Method m = classz[0].getMethod(method, parameterTypes);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m
.getAnnotation(DataSource.class);
DataSourceHolder.setDataSource(data.value());
log.info("数据源的获取 DataSource: "+data.value());
}
} catch (Exception e) {
log.error("数据源的获取 aop实现 出错:"+e.getMessage());
}
}
}
c、DataSourceHolder 数据源操作 获取数据源 帮助类
package com.ifengSearch.common.database;
/**
* 多数据源
* 数据源操作 获取数据源
* @author flm
* @2017年9月12日
*/
public class DataSourceHolder {
//线程本地环境
private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();
//设置数据源
public static void setDataSource(String customerType) {
dataSources.set(customerType);
}
//获取数据源
public static String getDataSource() {
return (String) dataSources.get();
}
//清除数据源
public static void clearDataSource() {
dataSources.remove();
}
}
d、 我们还需要实现spring的抽象类AbstractRoutingDataSource,就是实现determineCurrentLookupKey方法:
package com.ifengSearch.common.database;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 多数据源
* 获取数据源(依赖于spring)
* @author flm
* @2017年9月12日
*/
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSource();
}
}
4、接下来就可以看结果了
我在dao层直接调用
public interface UserDao {
/**
* 登录判断 【数据源B】
*/
@DataSource(value=DataSource.dataSourceB)
public List<UserBean> getLoginUserList(@Param("loginName")String loginName,@Param("loginPwd")String loginPwd);
/**
* 查找上一级 服务商 【数据源A】
*/
@DataSource(value=DataSource.dataSourceA)
public UserBean getServerUser(@Param("u_last_id")Integer u_last_id);
}
总结
以上所述是小编给大家介绍的Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# mybatis
# 读写分离
# aop
# spring
# aop读写分离
# Spring AOP使用接口方式实现
# Springboot接口项目如何使用AOP记录日志
# Spring AOP实现Redis缓存数据库查询源码
# Spring AOP切面解决数据库读写分离实例详解
# 使用Spring AOP实现MySQL数据库读写分离案例分析(附demo)
# Spring AOP实现接口请求记录到数据库的示例代码
# 连接池
# 多个
# 新和
# 小编
# 都是
# 数据查询
# 几个
# 我在
# 在此
# 给大家
# 跟你
# 较多
# 自定义
# 还需要
# 多说
# 较少
# 较长
# 所述
# 写上
# 给我留言
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
laravel怎么配置和使用PHP-FPM来优化性能_laravel PHP-FPM配置与性能优化方法
laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法
Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案
DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解
Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询
Laravel PHP版本要求一览_Laravel各版本环境要求对照
bing浏览器学术搜索入口_bing学术文献检索地址
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
js代码实现下拉菜单【推荐】
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
Laravel用户密码怎么加密_Laravel Hash门面使用教程
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
UC浏览器如何设置启动页 UC浏览器启动页设置方法
原生JS获取元素集合的子元素宽度实例
作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】
昵图网官网入口 昵图网素材平台官方入口
Laravel如何实现事件和监听器?(Event & Listener实战)
七夕网站制作视频,七夕大促活动怎么报名?
Claude怎样写结构化提示词_Claude结构化提示词写法【教程】
如何撰写建站申请书?关键要点有哪些?
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境
如何在服务器上三步完成建站并提升流量?
ChatGPT怎么生成Excel公式_ChatGPT公式生成方法【指南】
Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives
PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】
Bootstrap CSS布局之列表
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
Python函数文档自动校验_规范解析【教程】
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
Java类加载基本过程详细介绍
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件
如何自定义建站之星网站的导航菜单样式?
Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复
宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程
如何获取上海专业网站定制建站电话?
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
如何在腾讯云服务器上快速搭建个人网站?
如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体
成都网站制作公司哪家好,四川省职工服务网是做什么用?
浅析上传头像示例及其注意事项
香港服务器租用费用高吗?如何避免常见误区?
Python3.6正式版新特性预览
如何有效防御Web建站篡改攻击?
微信小程序 五星评分(包括半颗星评分)实例代码
Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】
如何快速搭建二级域名独立网站?
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
如何正确下载安装西数主机建站助手?
上一篇:nginx配置优化实例分析
上一篇:nginx配置优化实例分析

