如何编程实现从多数据库操作数据
对于数据量很大的复杂系统,有时候会采用分库或者分表的减轻单台数据库服务器压力,截止目前有一些工具直接支持读写分离等,例如ShardingSphere,如果不采用工具框架,从编码出发,如何实现从多个数据库读写数据呢?本篇博客将介绍三种代码实现思路,并提供完整Demo。
方式一:将不同DB的操作存放到不同目录下来实现分库操作
通过该方式达到分库的操作,实际很简单,第一:在application.properties文件中通过不同的前缀区分不同的数据库,第二:为不同的database编写配置类,在配置类中定义了repository的目录,通过前缀创建不同的Database bean,第三,在不同的目录编写service,repository,controller.这样在不同controller调用service,service再调用repository时,因为不同的数据库配置的repository目录不同,故调用不同controller时,实际使用的是不同的数据库。这种实现思路,本质实现的目标是将不同的表放入不同Database中,并不是将相同的表放入不同的数据库,例如读写分离。完整代码可查看Demo1。

方式二:通过切面编程实现读写分离
实际业务场景中,为了提升数据库处理数据能力,可能需要进行读写分离,即同一张表,写操作在一个数据库,读操作在另外一个数据库,这两个数据库存放了相同的表数据。那如何编写代码实现这一目标呢?如下图所示,首先在application.properties文件中,通过不同的前缀来区分数据库,在配置文件类中定义不同DataSource bean,接着在切面代码中,如果方法是以find,select,query,search等开头,那么去查询slave数据库,否则从master数据库操作数据,这样就实现了读写分离。

上面代码片段中本质是通过DataSourceContextHolder来切换数据库的?而DataSourceContextHolder本身只有一些get(),set()方法,背后是如何工作的呢?如下图代码所示,在定义EntityManagerFactoryBean的时候注入了routingDataSource,而RoutingDataSource默认会设置masterDataSource为默认的目标数据库,当通过DataSourceContextHolder重新设置目标数据库后,RoutingDataSource中的目标数据库会同步更新,而EntityManagerFactoryBean是通过routingDataSource构建出来的,所以,最终实现了不同数据库的切换操作。完整代码可查看Demo2。

方式三:通过切面编程实现分表
如下图所示,虽然都是通过切面编程的方式,但是这个切面是针对注解,当添加注解@SwithDataSource(value="xxdb")时,下面的repository都切换到了对应的数据库,右边图片是切面编程的部分代码,本质是调用AbstractRoutingDataSourceImpl.setDatabaseName(annotation.value())。

那AbstractRoutingDataSourceImpl是如何实现数据库切换的呢?查看AbstractRoutingDataSourceImpl的代码,overwrite中只有一些get(),set()方法。接着查看定义entityManagerFactoryBean的class,在这个class中定义了entityManagerFactoryBean,dataSource()这个bean中设置了默认default的database,当设置新的database后,完成数据库的切换。完整代码细节可查看demo3.


从前面的三个例子看,使用多个数据源时,Entity和Repository不用修改。只要设置好@EnableJpaRepositories,就能让Repository找到正确的数据源,自动装配。其中主要的两个参数是创建Entity的entityManagerFactoryRef和创建Repository的transactionManagerRef。为了创建EntityManagerFactory,我们需要借助DataSourceProperties创建DataSource对象。而使用@ConfigurationProperties,可以自动从配置文件生成DataSourceProperties。创建TransactionManager则需要指定SQL方言。方言类名可以通过Environment从配置中读取。从上面例子中可以看到,都是通过EntityManagerFactoryBuilder创建了LocalContainerEntityManagerFactoryBean,那LocalContainerEntityManagerFactoryBean的作用是什么呢?实际JPA 定义了两种类型的实体管理器:
应用程序管理类型(Application-managed):当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开或关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在 Java EE 容器中的独立应用程序。
容器管理类型(Container-managed):实体管理器由 Java EE 创建和管理。应用程序根本不与实体管理器工厂打交道。相反,实体管理器直接通过注入或 JNDI 来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适用于 Java EE 容器,在这种情况下会希望在 persistence.xml 指定的 JPA 配置之外保持一些自己对 JPA 的控制。
这对想使用 JPA 的 Spring 开发者来说又意味着什么呢?其实这并没太大的关系。不管你希望使用哪种 EntityManagerFactory,Spring 都会负责管理 EntityManager。如果你使用的是应用程序管理类型的实体管理器,Spring 承担了应用程序的角色并以透明的方式处理 EntityManager。在容器管理的场景下,Spring 会担当容器的角色。这两种实体管理器工厂分别由对应的 Spring 工厂 Bean 创建:
LocalEntityManagerFactoryBean 生成应用程序管理类型的 EntityManagerFactory;
LocalContainerEntityManagerFactoryBean 生成容器管理类型的 EntityManagerFactory。
EntityManagerFactoryBuilder采用构造者模式,传说数据库连接相关信息,即可完成对数据库的访问。

实现数据源切换用到了AbstractRoutingDataSource,该class包含的常见的属性以及含义如下:
targetDataSources是目标数据源集合
defaultTargetDataSource是默认数据源
resolvedDataSources是解析后的数据源集合
resolvedDefaultDataSource是解析后的默认数据源
要实现数据源切换,实际是自定义一个类扩展AbstractRoutingDataSource抽象类,相当于数据源DataSourcer的路由中介,可以实现在项目运行时根据相应key值切换到对应的数据源DataSource上。先看看AbstractRoutingDataSource的源码:

从源码可以看出AbstractRoutingDataSource继承了AbstractDataSource并实现了InitializingBean,AbstractRoutingDataSource的getConnection()方法调用了determineTargetDataSource()的该方法,这里重点看determineTargetDataSource()方法代码,方法里使用到了determineCurrentLookupKey()方法,它是AbstractRoutingDataSource类的抽象方法,也是实现数据源切换要扩展的方法,该方法的返回值就是项目中所要用的DataSource的key值,拿到该key后就可以在resolvedDataSource中取出对应的DataSource,如果key找不到对应的DataSource就使用默认的数据源。
自定义类扩展AbstractRoutingDataSource类时就是要重写determineCurrentLookupKey()方法来实现数据源切换功能,具体代码如下所示:

以上就是对于多数据库切换的介绍。
相关文章:
如何编程实现从多数据库操作数据
对于数据量很大的复杂系统,有时候会采用分库或者分表的减轻单台数据库服务器压力,截止目前有一些工具直接支持读写分离等,例如ShardingSphere,如果不采用工具框架,从编码出发,如何实现从多个数据库读写数据…...
LeetCode 147. 对链表进行插入排序 | C/C++版
LeetCode 147. 对链表进行插入排序 | C语言版LeetCode 147. 对链表进行插入排序题目描述解题思路思路一:使用栈代码实现运行结果参考文章:思路二:减少遍历节点数代码实现运行结果参考文章:[]()LeetCode 147. 对链表进行插入排序 …...
【QT进阶】第五章 QT绘图之自定义控件--仪表盘绘制
❤️作者主页:凉开水白菜 ❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步! ❤️专栏目录:【零基础学QT】文章导航篇 ❤️专栏资料:https://pan.baidu.com/s/192A28BTIYFHmixRcQwmaHw 提取码:qtqt ❤️点赞 👍 收藏 ⭐再看,养成习惯 订阅的粉丝可通过…...
Java代码弱点与修复之——URL manipulation(URL操纵)
弱点描述 “URL manipulation” 是指攻击者利用应用程序中的 URL 参数来执行恶意操作的一种攻击技术。 在 URL manipulation 攻击中,攻击者会修改应用程序中的 URL 参数,以便执行不当操作,如访问未授权的页面、修改他人的数据、绕过访问控制等。攻击者通常会使用手动修改 …...
Sharding Sphere学习
一、基本概念 1.什么是Sharding Sphere 2.分库分表3.分库分表的方式 4.分库分表应用和问题 5.功能 5.1数据分片 —核心概念 —使用限制 5.2分布式事务 —核心概念 —使用限制 5.3读写分离 —核心概念 —使用限制 5.4高可用 —核心概念 —使用限制 5.5数据库网关 —核心概念…...
粗心小编被云拯救,那云上数据谁来拯救?
开工第三天 小编已忙的焦头烂额 不是因为工作积压 而是因为自己的疏忽 也许是没有进入工作状态,一大早先经历了自行车钥匙丢失,手机遗落在家,好不容易坐到工位上才发现,备份数据的U盘忘带了。 不过,好在提前将工作文件上传到了云端…...
[git可视化软件]gitkraken平替:GitAhead
日期2023-02-28 gitkraken6.5.1已经不能登陆使用了!! 6.5.1免费版已经无法使用!!! 现在是2023-02-28 这款工具已经废除了6.5.1版本的使用功能了,我直接卡在登陆界面进不去项目了. 要想继续管理私有项目,只能升级最新版的软件,并且开通会员.会员费用高的一批,一年要59.4美元.约…...
CentOS8基础篇8:使用systemctl管理NFS服务
一、服务简介 服务:是指执行指定系统功能的程序、例程或进程,以便支持其他程序,尤其是底层(接近硬件)程序。 例如:打印服务,ftp服务,http服务。 服务就是一个程序(正在执行的程序)…...
Go defer用法
defer概览 defer是go语言里的一个关键字,在 函数内部使用;defer关键字后面跟一个 函数或匿名函数; defer用法 执行一些资源的收尾工作,如 关闭数据库连接,关闭文件描述符,释放资源等等;结合recover()函数使用,防止函数内部的异常导致整个程序停止;defer在遇到panic后,仍然会…...
产地证是什么,主要作用有哪些?
产地证是什么,主要作用有哪些?最近一个客户问我,产地证是什么,主要作用有哪些?今天就来扒拉扒拉这个问题,其实很简单~通俗一点的讲,产地证是货物原产地的证明文件之一,主要用于国外清…...
王道计算机网络课代表 - 考研计算机 第一章 计算机网络体系结构 究极精华总结笔记
本篇博客是考研期间学习王道课程 传送门 的笔记,以及一整年里对 计算机网络 知识点的理解的总结。希望对新一届的计算机考研人提供帮助!!! 关于对 “计算机网络体系结构” 章节知识点总结的十分全面,涵括了《计算机网络…...
数据处理 |遍历所有文件夹及子目录文件夹方法总结与实例代码详解
深度学习中不可避免的数据预处理~1. glob.glob()方法 2. pathlib中的Path方法3. os.walk()方法1. glob.glob()方法 语法glob.glob(pathname)(多指定文件类型,查找jpg,png,txt,json等)缺点:查找文件较慢2. 路径操作库pathlib中的Pa…...
ProtoEditor - 如何在Unity中实现一个Protobuf通信协议类编辑器
文章目录简介Protobuf 语法规则Proto Editor实现创建窗口定义类、字段增删类编辑字段导入、导出Json文件生成.proto文件生成.bat文件简介 在Socket网络编程中,假如使用Protobuf作为网络通信协议,需要了解Protobuf语法规则、编写.proto文件并通过编译指令…...
2022 OpenCV Spatial AI大赛前三名项目分享,开源、上手即用,优化了OAK智能双目相机的深度效果。
编辑:OAK中国 首发:oakchina.cn 喜欢的话,请多多👍⭐️✍ 内容可能会不定期更新,官网内容都是最新的,请查看首发地址链接。 ▌前言 Hello,大家好,这里是OAK中国,我是助手…...
Android 蓝牙开发——HCI log 分析(二十)
HCI log 是用来分析蓝牙设备之间的交互行为是否符合预期,是否符合蓝牙规范。对于蓝牙开发者来说,通过 HCI log 可以帮助我们更好地分析问题,理解蓝牙协议。 一、抓取HCI log 1、手机抓取HCI log 在开发者选项中打开启用蓝牙HCI信息收集日志开关,Android系统就开始自动地收…...
flask入门-4.项目实战
4. 项目实战1 1. 问答平台项目结构搭建 项目结构 config.py hostname "127.0.0.1" port 3306 username "root" password "root"database "flask_qa"# 在 app.config 中设置连接数据库的信息 SQLALCHEMY_DATABASE_URI f"…...
java 1(概要、变量与运算符)
java ——概要、变量与运算符 ✍作者:电子科大不知名程序员 🌲专栏:java学习指导 各位读者如果觉得博主写的不错,请诸位多多支持;如果有错误的地方,欢迎在评论区指出 目录java ——概要、变量与运算符命令行…...
力扣解法汇总2363. 合并相似的物品
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给你两个二维整数数组 items1 和 items2 ,表示两个物品集合。每个数…...
2022年终总结-找回初心
和“那个夏天”群聊的几位死党聊完天后,发现自己已经忘了初心2年有余了,也是这次聊天让我重新燃起了要继续努力奋斗的想法。那就说一说2022年我过得如何吧。2022年过完春节刚来公司的几天就传来了一个好消息,我涨薪了。在没有涨薪之前私下有时…...
Allegro如何打开或者关闭DFA规则设置操作指导
Allegro如何打开或者关闭DFA规则设置操作指导 在用Allegro做PCB布局的时候,器件与器件之间的DFA规则可以避免器件出现装配问题。如下图 当DFA规则设置好之后,如何打开或者关闭规则,具体操作如下 点击Setup点击Constraints...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
