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 数据库读写分离的更多相关文章

  1. Spring + Mybatis项目实现数据库读写分离

    主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 & ...

  2. Spring+mybatis 实现aop数据库读写分离,多数据库源配置

    在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库.Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询.因为在实际的应用中,数据库都是读多写少 ...

  3. spring+mybatis利用interceptor(plugin)兑现数据库读写分离

    使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是"地位相当"的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这 ...

  4. Spring+MyBatis实现数据库读写分离方案

    推荐第四种:https://github.com/shawntime/shawn-rwdb 方案1 通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactor ...

  5. Spring aop应用之实现数据库读写分离

    Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...

  6. 161220、使用Spring AOP实现MySQL数据库读写分离案例分析

    一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...

  7. MyBatis多数据源配置(读写分离)

    原文:http://blog.csdn.net/isea533/article/details/46815385 MyBatis多数据源配置(读写分离) 首先说明,本文的配置使用的最直接的方式,实际用 ...

  8. 170301、使用Spring AOP实现MySQL数据库读写分离案例分析

    使用Spring AOP实现MySQL数据库读写分离案例分析 原创 2016-12-29 徐刘根 Java后端技术 一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案 ...

  9. 使用Spring AOP实现MySQL数据库读写分离案例分析

    一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...

随机推荐

  1. Python进阶:@property 动态属性

    Python进阶:@property 动态属性 Python 动态属性的概念可能会被面试问到,在项目当中也非常实用,但是在一般的编程教程中不会提到,可以进修一下. 先看一个简单的例子.创建一个 Stu ...

  2. HDU 5861 Road(线段树 区间修改 单点查询)

    Road Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  3. Flask实战第43天:把图片验证码和短信验证码保存到memcached中

    前面我们已经获取到图片验证码和短信验证码,但是我们还没有把它们保存起来.同样的,我们和之前的邮箱验证码一样,保存到memcached中 编辑commom.vews.py .. from utils i ...

  4. jdbc 回顾

    JDBC实现基本的CRUD示例 private static void insertTest() throws SQLException { String dbURL = "jdbc:mys ...

  5. python搜索引擎(转)

    用python如何实现一个站内搜索引擎? 先想想搜索引擎的工作流程: 1.网页搜集.用深度或者广度优先的方法搜索某个网站,保存下所有的网页,对于网页的维护采用定期搜集和增量搜集的方式. 2.建立索引库 ...

  6. 最近升级mysql5.7出现下面问题,ORDER BY clause is not in GROUP BY..this is incompatible with sql_mode=only_full_group_by

    执行sql: SELECT * FROM `user_link` WHERE `group_id` IN ('78', '79') GROUP BY `link_id` 报错: SQLSTATE[42 ...

  7. Java 生产者消费者 & 例题

    Queue http://m635674608.iteye.com/blog/1739860 http://www.iteye.com/problems/84758 http://blog.csdn. ...

  8. [BZOJ4709][JSOI2011]柠檬(斜率优化DP)

    显然选出的每一段首尾都是相同的,于是直接斜率优化,给每个颜色的数开一个单调栈即可. #include<cstdio> #include<vector> #include< ...

  9. BZOJ 4027:[HEOI2015]兔子与樱花(贪心+树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4027 [题目大意] 樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1 ...

  10. bzoj 1734: [Usaco2005 feb]Aggressive cows 愤怒的牛

    1734: [Usaco2005 feb]Aggressive cows 愤怒的牛 Description Farmer John has built a new long barn, with N ...