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. Single Number II(LintCode)

    Single Number II Given 3*n + 1 numbers, every numbers occurs triple times except one, find it. Examp ...

  2. linux shell date 用当天时间做备份文件名

    #!/bin/bash #date  显示时间,我们可以用时间的不同做为备份文件的名字,这样以前的备份就不会被覆盖 datename=$(date +%Y%m%d-%H%M%S)           ...

  3. ubuntu14.04下安装爬虫工具scrapy

    scrapy是目前准备要学习的爬虫框架,其在ubuntu14.04下的安装过程如下: ubuntu14.04下默认安装了2.7的python以及setuptools,若未安装,可通过下面指令安装: s ...

  4. 【BZOJ 4104】【THUSC 2015】解密运算

    http://www.lydsy.com/JudgeOnline/problem.php?id=4104 网上题解满天飞,我也懒得写了 #include<cstdio> #include& ...

  5. [Lydsy1806月赛] 路径统计

    题面在这里! xjb想的做法竟然不小心把std艹爆了qwq,我也很无奈啊.... 那接下来就说一下我的神奇做法qwq 如果是经常读我博客的童鞋会发现其实我以前就想要做这个题啦,只不过当时读错题啦... ...

  6. BZOJ 2225 [Spoj 2371]Another Longest Increasing(CDQ分治)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2225 [题目大意] 给定N个数对(xi,yi),求最长上升子序列的长度. 上升序列定义 ...

  7. 【SAM】BZOJ2882-工艺

    [题目大意] 求一个循环数列的最小表示法. [思路] 最小表示法的正解:★ SAM乱搞,和前面的POJ那道一样.然而MLE了,当作学习一下map的用法^ ^ map的使用方法(来源:☆) 一.map的 ...

  8. (原创)Stanford Machine Learning (by Andrew NG) --- (week 5) Neural Networks Learning

    本栏目内容来自Andrew NG老师的公开课:https://class.coursera.org/ml/class/index 一般而言, 人工神经网络与经典计算方法相比并非优越, 只有当常规方法解 ...

  9. Fork & vfork & clone (转载)

    转自:http://blog.csdn.net/zqy2000zqy/archive/2006/09/04/1176924.aspx 进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合, ...

  10. iOS开发利器-CocoaPods安装和使用教程

    新博客http://www.liuchendi.com 开发iOS项目时肯定会用到许多第三方项目,比如说:ASIHttprequest,JSONKit等等,一些类库可能又关联着其他类库,如果超过一定的 ...