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

网友投稿 315 2022-12-09


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(test2Usernamehttp://);

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;

}

}

定义一个枚http://举类管理数据源

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 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 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);

}

总结

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java包装类原理与用法实例分析
下一篇:SpringCloud Feign服务调用请求方式总结
相关文章

 发表评论

暂时没有评论,来抢沙发吧~