SpringBoot Mybatis动态数据源切换方案实现过程

 更新时间:2020年04月17日 10:01:21   作者:经典鸡翅  
这篇文章主要介绍了SpringBoot+Mybatis实现动态数据源切换方案过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

背景

最近让我做一个大数据的系统,分析了一下,麻烦的地方就是多数据源切换抽取数据。考虑到可以跨服务器跨数据库抽数,再整理数据,就配置了这个动态数据源的解决方案。在此分享给大家。

实现方案

数据库配置文件

我们项目使用的是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);

 }

总结

至此实现了多数据源的动态切换。可以在同一个方法里面进行操作多个数据源。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java并发编程 interrupt()方法示例详解

    Java并发编程 interrupt()方法示例详解

    interrrupt()方法可以用来打断正在运行的线程,也可以打断sleep()、wait()、join()情况下的线程,但是这些情况下被打断线程的打断标记不同,这篇文章主要介绍了Java并发编程 interrupt()方法示例详解,需要的朋友可以参考下
    2023-06-06
  • java获取文件扩展名的方法小结【正则与字符串截取】

    java获取文件扩展名的方法小结【正则与字符串截取】

    这篇文章主要介绍了java获取文件扩展名的方法,结合实例形式分析了使用正则与字符串截取两种获取扩展名的操作技巧,需要的朋友可以参考下
    2017-01-01
  • java正则替换sql中的参数实例代码

    java正则替换sql中的参数实例代码

    这篇文章主要给大家介绍了关于java正则替换sql中参数的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-10-10
  • Java利用EasyExcel解析动态表头及导出实现过程

    Java利用EasyExcel解析动态表头及导出实现过程

    以前做导出功能,表头和数据都是固定的,下面这篇文章主要给大家介绍了关于Java利用EasyExcel解析动态表头及导出实现的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • 使用SpringBoot自定义starter详解

    使用SpringBoot自定义starter详解

    这篇文章主要介绍了使用Spring Boot自定义starter详解,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好地帮助哟,需要的朋友可以参考下
    2021-05-05
  • 基于IOC容器实现管理mybatis过程解析

    基于IOC容器实现管理mybatis过程解析

    这篇文章主要介绍了基于IOC容器实现管理mybatis过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • mybatis plus动态数据源切换及查询过程浅析

    mybatis plus动态数据源切换及查询过程浅析

    这篇文章主要介绍了mybatis plus动态数据源切换及查询过程浅析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • maven插件maven-assembly-plugin打包归纳文件zip/tar使用

    maven插件maven-assembly-plugin打包归纳文件zip/tar使用

    java项目运行的文件需要jar或者war格式,同时还需要使用Java命令,本文主要介绍了maven插件maven-assembly-plugin打包归纳文件zip/tar使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • Guava事件总线应用场景最佳实践

    Guava事件总线应用场景最佳实践

    这篇文章主要为大家介绍了Guava事件总线应用场景最佳实践,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • 使用SpringBoot 工厂模式自动注入到Map

    使用SpringBoot 工厂模式自动注入到Map

    这篇文章主要介绍了使用SpringBoot 工厂模式自动注入到Map,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论