SpringBoot Mybatis动态数据源切换方案实现过程
作者:经典鸡翅 发布时间:2022-10-12 03:25:03
背景
最近让我做一个大数据的系统,分析了一下,麻烦的地方就是多数据源切换抽取数据。考虑到可以跨服务器跨数据库抽数,再整理数据,就配置了这个动态数据源的解决方案。在此分享给大家。
实现方案
数据库配置文件
我们项目使用的是yml形式的配置文件,采用的是hikari的数据库连接池。第一步我们自然是配置多个数据库源头。
我们找到spring的datasource,在下方配置三个数据源。
spring:
application:
name: dynamicDatasource
datasource:
test1:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
test2:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
test3:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test3?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
hikari:
leak-detection-threshold: 2000
定义数据源实体类
我们可以建立个datasourceBean文件夹专门管理数据源的实体类。
我们这里要建立三个实体类。分别对应test1,test2,test3
@Configuration
public class Test1DataSourceBean {
@Value("${spring.datasource.test1.driver-class-name}")
private String test1Driver;
@Value("${spring.datasource.test1.url}")
private String test1Url;
@Value("${spring.datasource.test1.username}")
private String test1Username;
@Value("${spring.datasource.test1.password}")
private String test1Password;
@Bean(name="test1DataSource")
public DataSource test1DataSource() throws Exception{
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(test1Driver);
dataSource.setJdbcUrl(test1Url);
dataSource.setUsername(test1Username);
dataSource.setPassword(test1Password);
return dataSource;
}
}
@Configuration
public class Test2DataSourceBean {
@Value("${spring.datasource.test2.driver-class-name}")
private String test2Driver;
@Value("${spring.datasource.test2.url}")
private String test2Url;
@Value("${spring.datasource.test2.username}")
private String test2Username;
@Value("${spring.datasource.test2.password}")
private String test2Password;
@Bean(name="test2DataSource")
public DataSource test2DataSource() throws Exception{
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(test2Driver);
dataSource.setJdbcUrl(test2Url);
dataSource.setUsername(test2Username);
dataSource.setPassword(test2Password);
return dataSource;
}
}
@Configuration
public class Test3DataSourceBean {
@Value("${spring.datasource.test3.driver-class-name}")
private String test3Driver;
@Value("${spring.datasource.test3.url}")
private String test3Url;
@Value("${spring.datasource.test3.username}")
private String test3Username;
@Value("${spring.datasource.test3.password}")
private String test3Password;
@Bean(name="test3DataSource")
public DataSource test3DataSource() throws Exception{
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(test3Driver);
dataSource.setJdbcUrl(test3Url);
dataSource.setUsername(test3Username);
dataSource.setPassword(test3Password);
return dataSource;
}
}
定义一个枚举类管理数据源
public enum DatabaseType {
test1("test1", "test1"),
test2("test2", "test2"),
test3("test3","test3");
private String name;
private String value;
DatabaseType(String name, String value){
this.name = name;
this.value = value;
}
public String getName(){
return name;
}
public String getValue(){
return value;
}
}
定义一个线程安全的数据源容器
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
public static void setDatabaseType(DatabaseType type){
contextHolder.set(type);
}
public static DatabaseType getDatabaseType(){
return contextHolder.get();
}
}
定义动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource{
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDatabaseType();
}
}
mybatis配置类
网上的很多文章配置出来都会产生数据源循环依赖的问题,这里解决了这个问题。
@Configuration
@MapperScan(basePackages="cn.test.jichi", sqlSessionFactoryRef="sessionFactory")
public class MybatisConfig {
/**
* @Description:设置动态数据源
*/
@Bean(name="dynamicDataSource")
@Primary
public DynamicDataSource DataSource(
@Qualifier("test1DataSource") DataSource test1DataSource,
@Qualifier("test2DataSource") DataSource test2DataSource,
@Qualifier("test3DataSource") DataSource test3DataSource){
Map<Object, Object> targetDataSource = new HashMap<>();
targetDataSource.put(DatabaseType.test1, test1DataSource);
targetDataSource.put(DatabaseType.test2, test2DataSource);
targetDataSource.put(DatabaseType.test3, test3DataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSource);
dataSource.setDefaultTargetDataSource(test1DataSource);
return dataSource;
}
/**
* @Description:根据动态数据源创建sessionFactory
*/
@Bean(name="sessionFactory")
public SqlSessionFactory sessionFactory(
@Qualifier("test1DataSource") DataSource test1DataSource,
@Qualifier("test2DataSource") DataSource test2DataSource,
@Qualifier("test3DataSource") DataSource test3DataSource) throws Exception{
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
//构造方法,解决动态数据源循环依赖问题。
sessionFactoryBean.setDataSource(this.DataSource(test1DataSource,test2DataSource, test3DataSource));
return sessionFactoryBean.getObject();
}
}
示例
public void testDymnaicDatasource(){
//不切换数据源默认是自己的。
System.out.println("-----默认数据源");
DemoEntity totalCount = demoMapper.getTotalCount();
String nameCount1 = totalCount.getNameCount();
String ageCount2 = totalCount.getAgeCount();
System.out.println("nameCount:"+nameCount1);
System.out.println("ageCount:"+ageCount2);
//数据源切换为branch
System.out.println("-----数据源为test2");
DynamicDataSourceUtils.chooseBranchDataSource();
Integer nameCount = demoMapper.getNameCount();
Integer ageCount = demoMapper.getAgeCount();
System.out.println("nameCount:"+nameCount);
System.out.println("ageCount:"+ageCount);
//数据源为basic
System.out.println("-----数据源为test3");
DynamicDataSourceUtils.chooseBasicDataSource();
Integer ageCount1 = demoMapper.getAgeCount();
System.out.println("ageCount:"+ageCount1);
}
总结
至此实现了多数据源的动态切换。可以在同一个方法里面进行操作多个数据源。
来源:https://www.cnblogs.com/jichi/p/12013001.html


猜你喜欢
- 在过去十年中最流行的移动应用开发开发平台中,我们认为,Android平台是一个新开发的最方便的平台。一个廉价的工具,友好的开发者社区,众所周
- equalsIgnoreCase() 方法用于将字符串与指定的对象比较,不考虑大小写。实例equals() 会判断大小写区别,equalsI
- 在C#的List集合操作中,有时候需要查找到List集合中的最大值,此时可以使用List集合的扩展方法Max方法,Max方法有2种形式,一种
- Criteria的and和or进行联合查询DemoExample example=new DemoExample ();DemoExampl
- 1. 前言老板说,明天甲方要来看产品,你得造点数据,而且数据必须是“真”的,演示效果要好看一些,这样他才会买我们的产品,我好明年给你换个嫂子
- 这篇文章主要介绍了MyBatis传入数组集合类并使用foreach遍历,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学
- 简介本文主要讲解java代码如何利用selenium操作浏览器上传和下载文件代码教程。上传文件常见的 web 页面的上传,一般使用 inpu
- 何谓函数式编程相信大家在实际的开发中,很多情况下完成一个功能都需要借助多个类,那么我们这里的基本单元就是类。而函数式编程则更加细化,致使我们
- 本文实例讲述了Java循环队列原理与用法。分享给大家供大家参考,具体如下:在正式进行循环队列学习之前,我们先来看看在顺序队列中删除队首元素出
- 这篇文章主要介绍了Spring MVC4.1服务器端推送实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 为什么要在J2EE项目中谈异常处理呢?可能许多java初学者都想说:“异常处理不就是try….catch…finally吗?这谁都会啊!”。
- Mybatis是业界非常流行的持久层框架,轻量级、易用,在金融IT领域完全是领军地位,比Hibernate更受欢迎,优势非常多,也是非常值得
- java POI合并两个word文档有需要的可以将主函数中写死的地方改为一个Listimport java.io.FileInputStre
- Java中的多线程是一种抢占式的机制,而不是分时机制。抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行。 共同点: 1. 他们
- 排查@CacheEvict注解失效我简单看了一下《Spring实战》中的demo,然后就应用到业务代码中了,本以为如此简单的事情,竟然在代码
- mkdir函数用于创建目录。格式如下:#include<sys/types.h>#include<sys/stat.h&g
- mybatis初始化SqlSessionFactory失败总结原因有几点1.resources中的xml配置文件放错位置或者是放的太深加载不
- 什么是WebSocket?WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信—
- 使用例子如下,用JAVA 运行Sort1, 输入你要排序的文件路径 , 如 例子是对H:\下的文件和它所有子文件夹下的文件进行排序2, 输入
- 1. 前言Spring的核心技术IOC(Intorol of Converse控制反转)的实现途径是DI(dependency Insert