赞
踩
程序员黑哥 2023-08-30 22:13 发表于湖南
收录于合集
#计算机网络33个
#Java135个
#程序员89个
#编程75个

本文为 【Java多数据源实现教程】 相关知识,由于自己最近在做导师的项目的时候需要使用这种技术,于是自学了相关技术原理与实现,并将其整理如下,具体包含:多数据源的典型使用场景(包含业务复杂场景、读写分离场景),多数据源实现原理及实现方法(包含通过AbstractRoutingDataSource实现动态数据源、多数据源切换方式、Spring集成多个MyBatis框架实现多数据源),多数据源事务控制(包含只使用主库TransactionManger、一个方法开启2个事务),dynamic-datasource多数源组件等~
在实际开发中,经常可能遇到在一个应用中可能需要访问多个数据库的情况。以下是两种典型场景:
数据分布在不同的数据库中,数据库拆了, 应用没拆。一个公司多个子项目,各用各的数据库,涉及数据共享…

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即可实现动态数据源切换。
通过这个类可以实现动态数据源切换。如下是这个类的成员变量:
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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。