Springboot动态切换数据源的具体实现与原理分析

网友投稿 398 2022-09-09


Springboot动态切换数据源的具体实现与原理分析

目录前言具体实现:原理分析:总结

前言

在springboot项目中只需一句代码即可实现多个数据源之间的切换:

// 切换sqlserver数据源:

DataSourceContextHolder.setDataBaseType(DataSourceEnum.SQLSERVER_DATASOURCE);

......

// 切换mysql数据源

DataSourceContextHolder.setDataBaseType(DataSourceEnum.MYSQL_DATASOURCE);

具体实现:

本实例基于springboot2.5+版本实现。

1.配置数据源:

在配置文件中配置多个数据源的连接信息,用不同的前缀作为区别:

# sqlserver数据源1:前缀为:spring.datasource.sqlserver

spring.datasource.sqlserver.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver

spring.datasource.sqlserver.jdbc-url=jdbc:sqlserver://localhost:1433;DatabaseName=test

spring.datasource.sqlserver.username=sa

spring.datasource.sqlserver.password=sa

# mysql数据源1:前缀为:spring.datasource.mysql

spring.datasource.mysql.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.mysql.jdbc-url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true

spring.datasource.mysql.username=root

spring.datasource.mysql.password=root

# sqlLite数据源1:前缀为:spring.datasource.sqlite

spring.datasource.sqlite.driver-class-name=org.sqlite.JDBC

spring.datasource.sqlite.jdbc-url=jdbc:sqlite:D://sqllite//test.db

spring.datasource.sqlite.username=

spring.datasource.sqlite.password=

# sqlserver数据源2:前缀为:spring.datasource.sqlserver2

spring.datasource.sqlserver2.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver

spring.datasource.sqlserver2.jdbc-url=jdbc:sqlserver://localhost;DatabaseName=test1

spring.datasource.sqlserver2.username=sa

spring.datasource.sqlserver2.password=sa

# 配置数据库连接池信息

spring.datasource.hikari.maximum-pool-size=32

spring.datasource.hikari.minimum-idle=16

2.新建枚举类DataSourceEnum,有几个数据源对应设置几个枚举类。

public enum DataSourceEnum {

MYSQL_DATASOURCE,

SQLSERVER_DATASOURCE,

SQLSERVER2_DATASOURCE,

SQLLITE_DATASOURCE

}

3.新建数据库切换工具类DataSourceContextHolder,这里通过ThreadLocal类型的变量来存储当前数据源枚举类,同时能够保证线程安全。

public class DataSourceContextHolder {

/**

* 通过ThreadLocal保证线程安全

*/

private static final ThreadLocalhttp:// contextHolder = new ThreadLocal<>();

/**

* 设置数据源变量

* @param dataSourceEnum 数据源变量

*/

public static void setDataBaseType(DataSourceEnum dataSourceEnum) {

System.out.println("修改数据源为:" + dataSourceEnum);

contextHolder.set(dataSourceEnum);

}

/**

* 获取数据源变量

* @return 数据源变量

*/

public static DataSourceEnum getDataBaseType() {

DataSourceEnum dataSourceEnum = contextHolder.get() == null ? DataSourceEnum.MYSQL_DATASOURCE : contextHolder.get();

System.out.println("当前数据源的类型为:" + dataSourceEnum);

return dataSourceEnum;

}

/**

* 清空数据类型

*/

public static void clearDataBaseType() {

contextHolder.remove();

}

4.新建DynamicDataSource类继承AbstractRoutingDataSource类,并实现determineCurrentLookupKey方法,该方法是指定当前默认数据源的方法。

public class DynamicDataSouezixSNpkrce extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

return DataSourceContextHolder.getDataBaseType();

}

}

这个类看似内容不多,但其实继承了AbstractRoutingDataSource类是实现动态切换数据源的关键。

5.新建DataSourceConfig类用来创建bean的实例,其中包括各数据源的DataSource实例,DynamicDataSource实例以及跟Mybatis相关的SqlSessionFactory或Spring的JdbcTemplate实例。

@Configuration

public class DataSourceConfig {

@Bean(name = "sqlserverDataSource")

@ConfigurationProperties(prefix = "spring.datasource.sqlserver")

public DataSource getDateSource1() {

return DataSourceBuilder.create().build();

}

@Bean(name = "sqlserver2DataSource")

@ConfigurationProperties(prefix = "spring.datasource.sqlserver2")

public DataSource getDateSource11() {

return DataSourceBuilder.create().build();

}

@Bean(name = "mysqlDataSource")

@ConfigurationProperties(prefix = "spring.datasource.mysql")

public DataSource getDateSource2() {

return DataSourceBuilder.create().build();

}

@Bean(name = "sqlLiteDataSource")

@ConfigurationProperties(prefix = "spring.datasource.sqlite")

public DataSource getDateSource3() {

return DataSourceBuilder.create().build();

}

@Bean(name = "dynamicDataSource")

public DynamicDataSource DataSource(@Qualifier("sqlserverDataSource") DataSource sqlserverDataSource,

@Qualifier("sqlserver2DataSource") DataSource sqlserver2DataSource,

@Qualifier("mysqlDataSource") DataSource mysqlDataSource,

@Qualifier("sqlLiteDataSource") DataSource sqlLiteDataSource) {

//配置多数据源

Map targetDataSource = new HashMap<>();

targetDataSource.put(DataSourceEnum.SQLSERVER_DATASOURCE, sqlserverDataSource);

targetDataSource.put(DataSourceEnum.MYSQL_DATASOURCE, mysqlDataSource);

targetDataSource.put(DataSourceEnum.SQLLhttp://ITE_DATASOURCE, sqlLiteDataSource);

targetDataSource.put(DataSourceEnum.SQLSERVER2_DATASOURCE, sqlserver2DataSource);

DynamicDataSource dataSource = new DynamicDataSource();

//多数据源

dataSource.setTargetDataSources(targetDataSource);

//默认数据源

dataSource.setDefaultTargetDataSource(sqlserverDataSource);

return dataSource;

}

@Bean(name = "SqlSessionFactory")

public SqlSessionFactory test1SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)

throws Exception {

SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

bean.setDataSource(dynamicDataSource);

return bean.getObject();

}

@Bean(name = "JdbcTemplate")

public JdbcTemplate test1JdbcTemplate(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {

return new JdbcTemplate(dynamicDataSource);

}

}

这样就把我们切换数据库锁需要的bean全部交给spring容器中了,使用时直接通过DataSourceContextHolder.setDataBaseType(DataSourceEnum dataSourceEnum);这个方法指定数据源对应的枚举类即可。

原理分析:

其实我们新建数据库连接的时候也是通过DataSource来获取连接的,这里的AbstractRoutingDataSource也是通过了DataSource中的getConnection方法来获取连接的。

这个类里维护了两个Map来存储数据库连接信息:

@Nullable

private Map targetDataSources;

@Nullable

private Object defaultTargetDataSource;

privathttp://e boolean lenientFallback = true;

private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();

@Nullable

private Map resolvedDataSources;

@Nullable

private DataSource resolvedDefaultDataSource;

下面对上面的几个属性进行说明:

其中第一个targetDataSources是一个Map对象,在我们上面第五步创建DynamicDataSource实例的时候将多个数据源的DataSource类,放入到这个Map中去,这里的Key是枚举类,values就是DataSource类。

第二个defaultTargetDataSource是默认的数据源,就是DynamicDataSource中唯一重写的方法来给这个对象赋值的。

第三个lenientFallback是一个标识,是当指定数据源不存在的时候是否采用默认数据源,默认是true,设置为false之后如果找不到指定数据源将会返回null.

第四个dataSourceLookup是用来解析指定的数据源对象为DataSource实例的。默认是JndiDataSourceLookup实例,继承自DataSourceLookup接口。

第五个resolvedDataSources也是一个Map对象,这里是存放指定数据源解析后的DataSource对象。

第六个resolvedDefaultDataSource是默认的解析后的DataSource数据源对象上面的getConnection方法就是从这个变量中拿到DataSource实例并获取连接的。

总结


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

上一篇:华为S5735S系列交换机FTP配置(华为交换机s5731配置)
下一篇:网络通信知识地图
相关文章

 发表评论

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