Spring+mybatis 实现aop数据库读写分离,多数据库源配置
在数据库层面大都采用读写分离技术,就是一个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);
}
经过本人验证 测试页面 成功了
也可参考文章 http://www.cnblogs.com/surge/p/3582248.html
Spring+mybatis 实现aop数据库读写分离,多数据库源配置的更多相关文章
- spring+mybatis+mysql5.7实现读写分离,主从复制
申明:请尽量与我本博文所有的软件版本保持一致,避免不必要的错误. 所用软件版本列表:MySQL 5.7spring5mybaties3.4.6 首先搭建一个完整的spring5+springMVC5+ ...
- springboot+springAOP实现数据库读写分离及数据库同步(MySQL)----最新可用2019-2-14
原文:https://blog.csdn.net/wsbgmofo/article/details/79260896 1,数据源配置文件,如下 datasource.readSize=1spring. ...
- Spring + Mybatis项目实现数据库读写分离
主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 & ...
- Spring aop应用之实现数据库读写分离
Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...
- 161220、使用Spring AOP实现MySQL数据库读写分离案例分析
一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...
- spring+mybatis利用interceptor(plugin)兑现数据库读写分离
使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是"地位相当"的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这 ...
- Spring+MyBatis实现数据库读写分离方案
推荐第四种:https://github.com/shawntime/shawn-rwdb 方案1 通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactor ...
- 170301、使用Spring AOP实现MySQL数据库读写分离案例分析
使用Spring AOP实现MySQL数据库读写分离案例分析 原创 2016-12-29 徐刘根 Java后端技术 一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案 ...
- 使用Spring AOP实现MySQL数据库读写分离案例分析
一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...
- Spring AOP 实现读写分离
原文地址:Spring AOP 实现读写分离 博客地址:http://www.extlight.com 一.前言 上一篇<MySQL 实现主从复制> 文章中介绍了 MySQL 主从复制的搭 ...
随机推荐
- PHP面向对象中 static:: 与 self:: parent:: $this-> 的区别
很多好几年工作经验的PHP工程师,对PHP面向对象中 static:: .self::.parent::.$this-> 的定义和使用都不清晰,特做详细梳理: static:: 可以访问全局作 ...
- asm添加删除磁盘
一. ASM_POWER_LIMIT 参数 这个参数 ASM_POWER_LIMIT 参数控制 ASM 后台进程 ARBx 的数量.ARBx 进程用来进行 ASM 磁盘数据重新分布打散.ASM_POW ...
- Android学习笔记-ImageView(图像视图)
本节引言: 本节介绍的UI基础控件是:ImageView(图像视图),见名知意,就是用来显示图像的一个View或者说控件! 官方API:ImageView;本节讲解的内容如下: ImageView的s ...
- 如何查看appache的端口是否被占用
win + R 快捷键输入 cmd 打开命令行. 输入 netstat -ano 查看端口使用情况 Ctrl + Shift + Esc 打开 windows 任务管理器,依次单击 [查看][ 选择列 ...
- 27. leetcode 401. Binary Watch
A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom ...
- C/C++ 知识点---设计模式
在软件工程中,设计模式用来描述在各种不同情况下,要怎么解决问题的一种方案.面向对象设计模式通常以类或对象来描述其中的关系和相互作用,是软件“设计”层次上的问题.使用设计模式可提高代码的重用性和可靠性, ...
- Python 字典和集合
泛映射类型 collections.abc 模块中有 Mapping 和 MutableMapping 这两个抽象基类,它们的作用是为 dict 和其他类似的类型定义形式接口(在Python 2.6 ...
- Linux学习总结(十三)—— CentOS用户组管理:创建用户组、修改用户组、删除用户组
文章首发于[博客园-陈树义],请尊重原创保留原文链接. 在Linux系统里,有两个系统文件与用户组密切相关,它们分别是:/etc/group./etc/gshadow. /etc/group:存储了用 ...
- wpf软件某些分辨率下文字模糊解决方法
软件测试过程中发现在一台1600*900的分辨率电脑上文字模糊,甚至某些个文字出现压缩扭曲 经过实践,发现按下面方法能解决一点问题: 在窗口或控件上设置字体属性就可以了,如下: <UserCon ...
- softmax函数
该函数作用于输出层之上,用于改善输出层神经元饱和时与该神经元直接相关的w和bias学习率下降的问题. 定义: 这表明,在用柔性最大值函数定义输出神经元的输出时,神经元的输出是一种概率分布,所有输出层神 ...