当前位置:   article > 正文

【Java多数据源实现教程】实现动态数据源、多数据源切换方式_java多数据源切换

java多数据源切换

程序员黑哥 2023-08-30 22:13 发表于湖南

收录于合集

#计算机网络33个

#Java135个

#程序员89个

#编程75个

图片

本文为 【Java多数据源实现教程】 相关知识,由于自己最近在做导师的项目的时候需要使用这种技术,于是自学了相关技术原理与实现,并将其整理如下,具体包含:多数据源的典型使用场景(包含业务复杂场景、读写分离场景),多数据源实现原理及实现方法(包含通过AbstractRoutingDataSource实现动态数据源、多数据源切换方式、Spring集成多个MyBatis框架实现多数据源),多数据源事务控制(包含只使用主库TransactionManger、一个方法开启2个事务),dynamic-datasource多数源组件等~

一、多数据源的典型使用场景

在实际开发中,经常可能遇到在一个应用中可能需要访问多个数据库的情况。以下是两种典型场景:

1️⃣业务复杂(数据量大)

数据分布在不同的数据库中,数据库拆了, 应用没拆。一个公司多个子项目,各用各的数据库,涉及数据共享…

图片

2️⃣读写分离

  • 为了解决数据库的读性能瓶颈(读比写性能更高, 写锁会影响读阻塞,从而影响读的性能)。

  • 很多数据库拥主从架构。也就是,一台主数据库服务器,是对外提供增删改业务的生产服务器;另一(多)台从数据库服务器,主要进行读的操作。ꞏ

  • 可以通过中间件(ShardingSphere、mycat、mysql-proxy 、TDDL …),但是有一些规模较小的公司,没有专门的中间件团队搭建读写分离基础设施,因此需要业务开发人员自行实现读写分离。

图片

这里的架构与上图类似。不同的是,在读写分离中,主库和从库的数据库是一致的(不考虑主从延迟)。数据更新操作(insert、update、delete)都是在主库上进行,主库将数据变更信息同步给从库。在查询时,可以在从库上进行,从而分担主库的压力。

二、多数据源实现原理及实现方法

原理:

对于大多数的java应用,都使用了spring框架,spring-jdbc模块提供AbstractRoutingDataSource,其内部可以包含了多个DataSource,然后在运行时来动态的访问哪个数据库。这种方式访问数据库的架构图如下所示:

图片

应用直接操作的是AbstractRoutingDataSource的实现类,告诉AbstractRoutingDataSource访问哪个数据库,然后由AbstractRoutingDataSource从事先配置好的数据源(ds1、ds2)选择一个,来访问对应的数据库。

图片

  • (1)当执行数据库持久化操作,只要集成了Spring就一定会通过DataSourceUtils获取Connection

  • (2)通过Spring注入的DataSource获取Connection即可执行数据库操作。所以思路就是:只需配置一个实现了DataSource的Bean, 然后根据业务动态提供Connection即可

  • (3)其实Spring已经提供一个DataSource实现类用于动态切换数据源——AbstractRoutingDataSource

  • (4)分析AbstractRoutingDataSource即可实现动态数据源切换。

1️⃣通过AbstractRoutingDataSource实现动态数据源

通过这个类可以实现动态数据源切换。如下是这个类的成员变量:

private Map<Object, Object> targetDataSources;private Object defaultTargetDataSource;private Map<Object, DataSource> resolvedDataSources;
  • targetDataSources保存了key和数据库连接的映射关系

  • defaultTargetDataSource标识默认的连接

  • resolvedDataSources这个数据结构是通过targetDataSources构建而来,存储结构也是数据库标识和数据源的映射关系

而AbstractRoutingDataSource实现了InitializingBean接口,并实现了afterPropertiesSet方法。afterPropertiesSet方法是初始化bean的时候执行,通常用

作数据初始化。(resolvedDataSources就是在这里赋值)

@Overridepublic void afterPropertiesSet() {...this.resolvedDataSources = new HashMap<Object, DataSource(this.targetDataSources.size());//初始化resolvedDataSources//循环targetDataSources,并添加到resolvedDataSources中for (Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()) {Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());this.resolvedDataSources.put(lookupKey, dataSource);}...}
  • 所以,我们只需创建AbstractRoutingDataSource实现类DynamicDataSource然后初始化targetDataSources和key为数据源标识(可以是字符串、枚举、都行,因为标识是Object)、defaultTargetDataSource即可

  • 后续当调用AbstractRoutingDataSource.getConnection 会接着调用提供的模板方法:determineTargetDataSource

  • 通过determineTargetDataSource该方法返回的数据库标识从resolvedDataSources中拿到对应的数据源

  • 所以,我们只需DynamicDataSource中实现determineTargetDataSource为其提供一个数据库标识

总结,在整个代码中我们只需做4件大事:

  • (1)定义AbstractRoutingDataSource实现类DynamicDataSource

  • (2)初始化时为targetDataSources设置不同数据源的DataSource和标识、及defaultTargetDataSource

  • (3)在determineTargetDataSource中提供对应的数据源标识即可

  • (4)切换数据源标识即可

什么到这还不会?附上代码:

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/article/detail/52372?site

推荐阅读
相关标签