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


相关推荐: 软银砸40亿美元收购DigitalBridge 强化AI资料中心布局  html5audio标签播放结束怎么触发事件_onended回调方法【教程】  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?  Laravel如何构建RESTful API_Laravel标准化API接口开发指南  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  Laravel如何保护应用免受CSRF攻击?(原理和示例)  canvas 画布在主流浏览器中的尺寸限制详细介绍  晋江文学城电脑版官网 晋江文学城网页版直接进入  利用vue写todolist单页应用  Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程  如何快速生成ASP一键建站模板并优化安全性?  Swift中swift中的switch 语句  Android GridView 滑动条设置一直显示状态(推荐)  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  济南网站建设制作公司,室内设计网站一般都有哪些功能?  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  如何在橙子建站中快速调整背景颜色?  香港服务器选型指南:免备案配置与高效建站方案解析  EditPlus中的正则表达式 实战(2)  php增删改查怎么学_零基础入门php数据库操作必知基础【教程】  nginx修改上传文件大小限制的方法  如何用PHP快速搭建CMS系统?  Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  EditPlus中的正则表达式实战(6)  音响网站制作视频教程,隆霸音响官方网站?  如何正确下载安装西数主机建站助手?  如何确保FTP站点访问权限与数据传输安全?  网站制作免费,什么网站能看正片电影?  php结合redis实现高并发下的抢购、秒杀功能的实例  Laravel路由怎么定义_Laravel核心路由系统完全入门指南  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  魔毅自助建站系统:模板定制与SEO优化一键生成指南  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?  Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康  JavaScript如何实现继承_有哪些常用方法  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  在centOS 7安装mysql 5.7的详细教程  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  如何为不同团队 ID 动态生成多个非值班状态按钮  大型企业网站制作流程,做网站需要注册公司吗?  如何基于PHP生成高效IDC网络公司建站源码?  Laravel怎么实现验证码(Captcha)功能