当前位置: 首页 > news >正文

Spring中实现动态数据源切换,基于AbstractRoutingDataSource

背景

在项目开发过程中,我们可能会遇到一个场景:某个类型数据源有多个数据源实例,需要我们按照不同的请求切换到不同数据源去。
而目前绝大多数java应用都是基于Spring框架来开发,我们很多时候相关的数据源连接都是交给了Spring框架去管理,这就需要Spring能够支持动态数据源切换。

方案

Spring中预留了这个接口,通过AbstractRoutingDataSource能够动态切换数据源。

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {

这是一个抽象类,预留了一个抽象方法:

protected abstract Object determineCurrentLookupKey();

我们知道,数据源一般都会提供一个getConnection方法来获取一个连接,在AbstractRoutingDataSource 实现如下:

	@Overridepublic Connection getConnection() throws SQLException {return determineTargetDataSource().getConnection();}protected DataSource determineTargetDataSource() {Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");Object lookupKey = determineCurrentLookupKey();DataSource dataSource = this.resolvedDataSources.get(lookupKey);if (dataSource == null && (this.lenientFallback || lookupKey == null)) {dataSource = this.resolvedDefaultDataSource;}if (dataSource == null) {throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");}return dataSource;}

可以看到,AbstractRoutingDataSource 获取连接的主要逻辑就是通过determineCurrentLookupKey获取到一个数据源的关联key,然后从resolvedDataSources中去获取。
resolvedDataSources的初始化,则放在afterPropertiesSet中:

	@Overridepublic void afterPropertiesSet() {if (this.targetDataSources == null) {throw new IllegalArgumentException("Property 'targetDataSources' is required");}this.resolvedDataSources = CollectionUtils.newHashMap(this.targetDataSources.size());this.targetDataSources.forEach((key, value) -> {Object lookupKey = resolveSpecifiedLookupKey(key);DataSource dataSource = resolveSpecifiedDataSource(value);this.resolvedDataSources.put(lookupKey, dataSource);});if (this.defaultTargetDataSource != null) {this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);}}

这里起始就是通过targetDataSources中指定的数据源复制到resolvedDataSources 中去。因此如果多数源是固定的,那么只需要实现determineCurrentLookupKey方法即可。但是如果多数据源不固定,比如可能会有数据源的变更,那么这种实现是不能够支持,因为这种实现从服务启动的视乎,后续数据源就不能发生变更,这需要我们自己实现determineTargetDataSource.
下面是一个参考实现:

public class DataSourceContextHolder {private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();public static void switchDataSource(String key){log.info("Switch to data source:" + key);DATASOURCE_CONTEXT_KEY_HOLDER.set(key);}public static String getDataSourceKey(){return DATASOURCE_CONTEXT_KEY_HOLDER.get() ;}}public class DynamicDataSource extends AbstractRoutingDataSource {private Map<Object, Object> targetDataSources = new HashMap<>();private Map<Object, DataSource> dataSources = new HashMap<>();public DynamicDataSource (){super.setDefaultTargetDataSource(null);super.setTargetDataSources(targetDataSources);super.afterPropertiesSet();}@Overrideprotected DataSource determineTargetDataSource() {Object dataSourceKey = determineCurrentLookupKey();return dataSources.get(dataSourceKey);}@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder .getDataSourceKey();}public synchronized void addDataSource(String key, DataSource dataSource){targetDataSources.put(key,dataSource);dataSources.put(key,dataSource);log.info("add tenant dynamic dataSource for tenantId = {} ",key);}
}

这样我们通过DataSourceContextHolder 来调整当前线程关联的数据源。

http://www.lryc.cn/news/492848.html

相关文章:

  • StarRocks-join优化
  • js 高亮文本中包含的关键词标红
  • DVWA靶场——File Inclusion
  • Android Framework禁止弹出当前VOLTE不可用的提示窗口
  • OceanBase 大数据量导入(obloader)
  • w058基于web的美发门店管理系统
  • 实时数据开发 | checkpoints监控和调优
  • el-tree的使用及控制全选、反选、获取选中
  • 机器学习(二十五):决策树算法以及决策树和神经网络的对比
  • 新版布谷直播软件源码开发搭建功能更新明细
  • vue3 reactive响应式实现源码
  • git的使用(简洁版)
  • 使用命令行创建 Maven 项目
  • JVM_栈详解一
  • Linux 金仓数据库安装和使用
  • STM32笔记(串口IAP升级)
  • C++网络编程:select IO多路复用及TCP服务器开发
  • 部署 L2JMobius 天堂2芙蕾雅版本
  • C#开发合集
  • 鸿蒙面试 --- 性能优化
  • React的基础知识:Context
  • 微知-lspci访问到指定的PCIe设备的几种方式?(lspci -s bus;lspci -d devices)
  • 【Kubernetes 集群核心概念:Pod】pod生命周期介绍【五】
  • c++的虚继承说明、案例、代码
  • 小米PC电脑手机互联互通,小米妙享,小米电脑管家,老款小米笔记本怎么使用,其他品牌笔记本怎么使用,一分钟教会你
  • 介绍SSD硬盘
  • CMAKE常用命令详解
  • Vue3的通灵之术Teleport
  • ue5第三人称闯关游戏学习(一)
  • IIC 随机写+多次写 可以控制写几次