MyBatis SpringBoot2.0 数据库读写分离
1、自定义DataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /**
* @Description 动态数据源
* AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceType();
}
}
2、数据源切换器
import java.util.ArrayList;
import java.util.List; /**
* @Description 动态数据源上下文管理
*/
public class DynamicDataSourceContextHolder { //存放当前线程使用的数据源类型信息
private static final ThreadLocal<Object> contextHolder = new ThreadLocal<>();
//存放数据源id
public static List<Object> dataSourceIds = new ArrayList<>(); //当从库数据源大于1个时,可以配置轮询方式
public static List<Object> slaveDataSourceKeys = new ArrayList<>(); //设置数据源
public static void setDataSourceType(String dataSourceType) {
if(dataSourceIds.contains(dataSourceType)) {
contextHolder.set(dataSourceType);
}
} //获取数据源
public static Object getDataSourceType() {
return contextHolder.get();
} //清除数据源
public static void clearDataSourceType() {
contextHolder.remove();
}
}
3、代理类事物切换数据源
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; /**
* @Description 动态数据源通知
*/
@Aspect
@Order(-1)//保证在@Transactional之前执行
@Component
public class DynamicDattaSourceAspect { //改变数据源,方法上存在事物的注解,则走主库
@Before("@annotation(transactional)")
public void changeDataSource(JoinPoint joinPoint, Transactional transactional) {
DynamicDataSourceContextHolder.setDataSourceType("master");
} @After("@annotation(transactional)")
public void clearDataSource(JoinPoint joinPoint, Transactional transactional) {
DynamicDataSourceContextHolder.clearDataSourceType();
}
}
4、数据源Bean注册器
import java.util.HashMap;
import java.util.Map; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.flyway.FlywayDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; import tk.mybatis.spring.annotation.MapperScan; /**
* @Description 注册动态数据源
* 初始化数据源和提供了执行动态切换数据源的工具类
*/
@Configuration
@MapperScan(basePackages="com.xxxx.*.mapper")
public class DynamicDataSourceRegister{
protected Logger logger = LoggerFactory.getLogger(getClass()); @Value("${datasource.type}")
private Class<? extends DataSource> dataSourceType; @Bean
@Primary
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dynamicDataSource());
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath*:mapper/*Mapper.xml"));
Resource resource = pathMatchingResourcePatternResolver.getResource("classpath:mybatis-setting.xml");
sessionFactory.setConfigLocation(resource);
return sessionFactory.getObject();
} @FlywayDataSource//指定主库为flyway的数据源
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "master.datasource")
public DataSource masterDataSource(){
return DataSourceBuilder.create().type(dataSourceType).build();
} @Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "slave.datasource")
public DataSource slaveDataSource(){
return DataSourceBuilder.create().type(dataSourceType).build();
} @Bean("dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicRoutingDataSource = new DynamicDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(4);
dataSourceMap.put("master", masterDataSource());
dataSourceMap.put("slaveDataSource", slaveDataSource()); // 将 slave 数据源作为默认指定的数据源
dynamicRoutingDataSource.setDefaultTargetDataSource(slaveDataSource());
// 将 master 和 slave 数据源作为指定的数据源
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap); // 将数据源的 key 放到数据源上下文的 key 集合中,用于切换时判断数据源是否有效
DynamicDataSourceContextHolder.dataSourceIds.addAll(dataSourceMap.keySet()); // 将 Slave 数据源的 key 放在集合中,用于轮循
DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());
DynamicDataSourceContextHolder.slaveDataSourceKeys.remove("master");
return dynamicRoutingDataSource;
} @Bean
public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource());
} }
6、资源文件配置
#datasource master
datasource.type=com.alibaba.druid.pool.DruidDataSource
#master
master.datasource.url=jdbc:mysql://localhost:3306/haogonge_dev?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
master.datasource.username=root
master.datasource.password=root
master.datasource.driver-class-name=com.mysql.jdbc.Driver
master.datasource.pool.initialSize=3
master.datasource.pool.maxActive=15
master.datasource.pool.minIdle=3
master.datasource.pool.maxWait=60000
master.datasource.pool.timeBetweenEvictionRunsMillis=60000
master.datasource.pool.minEvictableIdleTimeMillis=120000
#slave
slave.datasource.url=jdbc:mysql://localhost:3306/haogonge_dev?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
slave.datasource.username=root
slave.datasource.password=root
slave.datasource.driver-class-name=com.mysql.jdbc.Driver
slave.datasource.pool.initialSize=3
slave.datasource.pool.maxActive=15
slave.datasource.pool.minIdle=3
slave.datasource.pool.maxWait=60000
slave.datasource.pool.timeBetweenEvictionRunsMillis=60000
slave.datasource.pool.minEvictableIdleTimeMillis=120000
MyBatis SpringBoot2.0 数据库读写分离的更多相关文章
- Spring + Mybatis项目实现数据库读写分离
主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 & ...
- Spring+mybatis 实现aop数据库读写分离,多数据库源配置
在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库.Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询.因为在实际的应用中,数据库都是读多写少 ...
- spring+mybatis利用interceptor(plugin)兑现数据库读写分离
使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是"地位相当"的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这 ...
- Spring+MyBatis实现数据库读写分离方案
推荐第四种:https://github.com/shawntime/shawn-rwdb 方案1 通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactor ...
- Spring aop应用之实现数据库读写分离
Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...
- 161220、使用Spring AOP实现MySQL数据库读写分离案例分析
一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...
- MyBatis多数据源配置(读写分离)
原文:http://blog.csdn.net/isea533/article/details/46815385 MyBatis多数据源配置(读写分离) 首先说明,本文的配置使用的最直接的方式,实际用 ...
- 170301、使用Spring AOP实现MySQL数据库读写分离案例分析
使用Spring AOP实现MySQL数据库读写分离案例分析 原创 2016-12-29 徐刘根 Java后端技术 一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案 ...
- 使用Spring AOP实现MySQL数据库读写分离案例分析
一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...
随机推荐
- div垂直居中的方法
在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中 ...
- 第2天:Ansible-Inventory管理
在Ansible中,将可管理的服务器集合成为Inventory.因此,Inventory管理便是服务器管理. hosts文件位置 我们知道,Ansible在执行操作时,首先需要确定对哪些服务器执行操作 ...
- luogu P3375 【模板】KMP字符串匹配
题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[ ...
- 【构造】【分类讨论】Codeforces Round #435 (Div. 2) C. Mahmoud and Ehab and the xor
题意:给你n,x,均不超过10^5,让你构造一个无重复元素的n个元素的非负整数集合(每个元素不超过10^6),使得它们的Xor和恰好为x. 如果x不为0: 随便在x里面找一个非零位,然后固定该位为0, ...
- 【kd-tree】hdu5992 Finding Hotels
比较裸的kd-tree,但是比较考验剪枝. 貌似除了经典的矩形距离剪枝之外, 还必须加个剪枝是某个矩形内的最小价格如果大于价格限制的话,则剪枝. #include<cstdio> #inc ...
- [BZOJ5351]Query on a sequence
[BZOJ5351]Query on a sequence 题目大意: 给定一个长度为\(n(n\le10^5)\)的数列\(P\),满足\(|P_i|\le10^9\),求满足下列约束的不同的四元组 ...
- Erlang学习记录(三)——表达式大集合
Erlang中的表达式必须以.结束才会去执行.如果不加.你在编译环境下按多少次Enter,表达式都不会执行,表达式之间可以用,分隔,以.结尾后所有的表达式都会执行,但是只有最后一个以.结尾的表达式会在 ...
- Uncaught SyntaxError: Invalid shorthand property initializer
$.ajax({ url : '../../collateralQuery/getCollateralQueryDetail', type : 'POST', data : {}, dataType ...
- <摘录>ldconfig和ldd用法
ldconfig和ldd用法 关键字: ldconfig ldd /etc/ld.so.conf LD_LIBRARY_PATH一.ldconfig ldconfig --helpUsage: ldc ...
- Vue 小项目的最佳实践
项目简介 目前一期只是为App内某个模块资讯模块文章的分享和APP下载,后续还会有更多的功能,为了项目可扩展.可伸缩结合了我以前的实践搭建了此项目项目地址,如果这个简单的项目能给您带来帮助请给小哥哥⭐ ...