数据库轻松切换:解读Spring中的AbstractRoutingDataSource

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

数据库轻松切换:解读Spring中的AbstractRoutingDataSource

    • 前言
    • AbstractRoutingDataSource介绍
      • 作用和优势:
        • 作用:
        • 优势:
      • 使用 AbstractRoutingDataSource 实现多数据源动态切换的理由:
    • 实现原理解析
    • 与其他数据源管理方式比较
      • 1. 与手动切换数据源比较:
      • 2. 与使用 AOP 切换数据源比较:
    • 注意事项与扩展功能

前言

在编程的世界里,就像是一场魔法表演,我们可以通过各种神奇的技巧创造出令人惊叹的效果。而在Spring框架中,AbstractRoutingDataSource就像是一把神奇的魔杖,能够让我们轻松地实现数据库的动态切换。它就像是一位智慧的导航员,能够帮助我们在复杂的数据库系统中找到正确的路线。现在,就让我们一起来揭开AbstractRoutingDataSource的神秘面纱,探索它的魅力所在吧!

AbstractRoutingDataSource介绍

AbstractRoutingDataSource 是 Spring 框架提供的一个抽象基类,专门用于实现数据源的动态路由。这个类继承自 javax.sql.DataSource,允许开发者根据当前的执行环境或者业务逻辑动态地切换到不同的数据源。

作用和优势:

作用:
  • 数据源动态切换AbstractRoutingDataSource 根据定义的路由规则(如当前的事务是否是只读事务),决定使用哪一个数据源。这在实现多租户系统或读写分离时非常有用,因为它允许同一个应用动态地针对不同的数据库操作,选择不同的数据源。
  • 简化配置:它使得配置多个数据源变得简单,可以在一个地方集中管理所有的数据源配置。
  • 透明访问:应用代码不需要关心当前使用的是哪个数据源,数据源的选择对业务逻辑是透明的。
优势:
  • 灵活性:它提供了在运行时根据业务规则选择合适数据源的能力,增加了应用的灵活性。
  • 减少代码重复:不需要在每个数据库操作中硬编码数据源选择逻辑,避免了代码重复。
  • 易于维护和扩展:中心化的数据源管理使得添加新的数据源或者更改现有数据源配置更加容易。
  • 与Spring集成AbstractRoutingDataSource 与 Spring 框架紧密集成,利用 Spring 的事务管理能力,可以无缝地与 Spring 事务一起工作。

使用 AbstractRoutingDataSource 实现多数据源动态切换的理由:

一致性AbstractRoutingDataSource 提供了一种标准的方式来处理多数据源的问题,确保了整个应用的数据源选择逻辑是一致的。

  • 事务管理:当与 Spring 的声明式事务管理一起使用时,可以确保数据源在整个事务中保持一致,而不会在事务的中间发生切换。
  • 减少配置错误:集中管理多个数据源配置减少了配置错误的可能性,并且使配置更加清晰。
  • 性能:在不牺牲性能的情况下实现了数据源的动态切换。
  • 解耦和透明性:业务代码不需要关心数据源的切换逻辑,这样可以更专注于业务本身,同时也降低了业务逻辑与数据访问层的耦合度。

总的来说,使用 AbstractRoutingDataSource 实现多数据源切换可以让应用保持高度的灵活性和可维护性,同时也能够与 Spring 的其他功能(如事务管理)无缝集成。

实现原理解析

AbstractRoutingDataSource 的工作原理其实很简单。它维护了一个 Map<Object, DataSource> 类型的数据源映射表,这个映射表用来存储标识符(一般是字符串或者枚举类型)到 DataSource 的映射关系。当需要获取连接时,AbstractRoutingDataSource 会调用 determineCurrentLookupKey() 方法来获取当前的标识符,然后根据这个标识符在映射表中查找对应的 DataSource

以下是 AbstractRoutingDataSource 工作流程的简化示意图:

+-----------------+        +---------------------+
| Application     |        | AbstractRouting    |
| (Transaction)   |        | DataSource         |
+-----------------+        +---------------------+
|                 |        | - determineCurrent  |
| begin           |        |   LookupKey()      |
| transaction     |        | - lookupDataSource |
+-----------------+        |   (lookupKey)      ||                  | - getConnection     ||                  |   ()                ||                  +---------------------+|                          |+------------------------->||                          ||        +--------------+  |  +-----------------+|        | DataSource   |  |  | DataSource     ||        | Mapping      |  |  | (Actual)       ||        +--------------+  |  +-----------------+|        | lookupKey   |   |  | - getConnection ||        | -> DataSource   |  |  |   ()         ||        +--------------+  |  +-----------------+|                          |          |+<-------------------------+          ||                                     ||                                     v|                             +-----------------+|                             | Database       ||                             +-----------------+|                             | - execute      ||                             |   SQL          |+---------------------------> | - return       ||                             |   result       |+<--------------------------- |                |v                             +-----------------+
+-----------------+
| Application     |
| (Transaction)   |
+-----------------+
| handle result   |
+-----------------+

在实际案例中,可以通过在业务代码中设置一个 ThreadLocal 变量来存储当前线程需要使用的数据源标识符,然后在 determineCurrentLookupKey() 方法中返回这个变量的值。例如,在一个多租户系统中,可以在用户登录时根据用户所属的租户设置数据源标识符,这样在后续的数据库操作中就会自动使用对应租户的数据源。

这是一个简单的示例:

public class TenantAwareRoutingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return TenantContext.getCurrentTenant();}}

在这个例子中,TenantContext.getCurrentTenant() 方法会返回当前线程中存储的租户标识符,然后 AbstractRoutingDataSource 会使用这个标识符来查找对应的 DataSource。这样,不同租户的请求就可以自动路由到对应的数据源,实现了租户级别的数据隔离。

总的来说,AbstractRoutingDataSource 的工作原理是通过维护一个数据源映射表并根据当前环境动态选择数据源,这使得它可以很容易地实现多数据源动态切换的需求。

与其他数据源管理方式比较

使用 AbstractRoutingDataSource 管理多数据源与其他方式相比,有以下优缺点:

1. 与手动切换数据源比较:

优点:

  • 自动化AbstractRoutingDataSource 能够自动根据指定的规则切换数据源,无需手动设置。
  • 透明性:业务代码不需要关心数据源的切换,降低了业务逻辑与数据访问层的耦合度。

缺点:

  • 配置复杂:相比于手动切换,AbstractRoutingDataSource 的配置相对复杂。

适用场景: 当需要根据业务规则自动切换数据源时,推荐使用 AbstractRoutingDataSource。例如,在实现多租户系统或读写分离时。

2. 与使用 AOP 切换数据源比较:

优点:

  • 灵活性AbstractRoutingDataSource 可以根据业务规则在运行时动态切换数据源,而 AOP 切换数据源通常在编译时就已经确定。
  • 性能AbstractRoutingDataSource 直接在获取连接时切换数据源,性能较好。而 AOP 切换数据源需要在每次数据库操作前后切换数据源,性能较差。

缺点:

  • 配置复杂:相比于 AOP 切换数据源,AbstractRoutingDataSource 的配置相对复杂。

适用场景: 当需要在运行时根据业务规则动态切换数据源,且对性能有要求时,推荐使用 AbstractRoutingDataSource。例如,在实现多租户系统或读写分离时。

总的来说,AbstractRoutingDataSource 提供了一种灵活且高效的方式来管理和切换多个数据源。虽然它的配置相对复杂,但是其自动化、透明性和性能优势使得它在很多场景下都是一个不错的选择。

注意事项与扩展功能

使用 AbstractRoutingDataSource 时,需要注意以下几点:

  1. 数据源切换的时机:数据源的切换应在当前事务开始之前进行,否则可能无法获取到正确的数据库连接。如果在事务中需要切换数据源,那么你可能需要将事务拆分为多个子事务。
  2. 线程安全:在多线程环境中,需要确保数据源键的存储方式是线程安全的。一种常见的做法是使用 ThreadLocal 来存储数据源键。
  3. 数据源的清理:在数据源使用完毕后,应当及时清理数据源键,以防止数据源键在其他地方被错误地重用。
  4. 事务管理器:在配置事务管理器时,应该使用 AbstractRoutingDataSource 作为数据源,而不是具体的数据源实例。

至于扩展功能,AbstractRoutingDataSource 可以用来实现许多高级的数据源管理需求,例如:

多租户支持:在多租户系统中,每个租户可能需要使用自己的数据库。此时,可以通过 AbstractRoutingDataSource 的子类来动态切换到正确的数据源。

读写分离:在读写分离的系统中,可以使用 AbstractRoutingDataSource 来根据当前的数据库操作(读或写)来选择据源。

数据库路由:在分布式数据库系统中,可以通过 AbstractRoutingDataSource 来根据某种路由算法(例如哈希或范围)来选择数据源。

总的来说,AbstractRoutingDataSource 提供了一种非常灵活的方式来管理和切换数据源,其可能的用途远不止这些。只要理解了其工作原理,你就可以根据自己的需求来定制和扩展它的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/644385.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Bugku-web】my-first-sqli

1.打开场景&#xff0c;用户名输入1 or 1 1 -- -&#xff0c;密码随便输。 2.得到flag值

Linux——NFS网络文件系统

在生产环境中共享宿主目录可以用于集中管理账户 一、存储设备 DAS 是直连存储相当于移动硬盘 NAS 是网络文件系统&#xff0c;挂载后可以直接访问 SAN 存储区域网络 IPSAN 网线连接 共享的是设备&#xff0c;需要挂载后分区使用 FCSAN 光纤连接 二、服务的管理 1、安…

Go Sync并发包之errgroup

你是否写过一个函数&#xff0c;它之所以很长&#xff0c;是因为它要完成很多任务&#xff0c;即使这些任务之间并不相互依赖&#xff1f; 你是否写过一个很长的函数&#xff0c;因为它要完成很多任务&#xff0c;即使这些任务并不相互依赖&#xff1f;我就遇到过这种情况。 想…

Esp32-S3 进行JSON解析

之前介绍了esp32-s3的http通信,对于返回的结果进行解析也是必须的,通常我们可以使用json格式进行通信,这样即便于理解也便于取值。今天我们介绍下JSON解析。 在这里用到的库是ujson,代码如下,将如下代码保存到设备即可 import micropython import json from json import …

【错题集-编程题】数组中的最长连续子序列(排序 + 模拟)

牛客对应链接&#xff1a;数组中的最长连续子序列_牛客题霸_牛客网 (nowcoder.com) 一、分析题目 排序 模拟。 注意&#xff1a;值连续&#xff0c;位置可以不连续&#xff01;小心处理数字相同的情况。 二、代码 //值得学习的代码 class Solution { public:int MLS(vecto…

python与上位机开发day02

1.常见运算符 1.1 赋值运算符 赋值运算符主要用来对变量进行赋值,包括如下这些: 运算符描述赋值加等于-减等于*乘等于/除等于//整除等于%模等于**幂等于 实例如下: a 10 a 5 # 等价于 a a5 a *2 # 等价于 a a*21.2 比较运算符 比较运算符主要用来比较两个数据的大小…

【Kafka】理论简介、消息队列(一)

简介 消息队列 为什么要有消息队列 图-1 消息队列的使用 消息队列 1)消息Message&#xff1a;网络中的两台计算机或者两个通讯设备之间传递的数据。例如说&#xff1a;文本、音乐、视频等内容。 2)队列Queue&#xff1a;一种特殊的线性表(数据元素首尾相接)&#xff0c;特殊…

「React Native」为什么要选择 React Native 作为的跨端方案

文章目录 前言一、常见因素二、举个栗子2.1 项目背景2.2 为什么选择 React Native2.3 项目实施2.4 成果总结 前言 没有完美的跨端技术&#xff0c;只有适合的场景。脱离适用场景去谈跨端技术没有什么意义。 一、常见因素 共享代码库&#xff1a; React Native 允许开发者编写…

新手必看十大地推网推拉新平台,副业从此不求人

现如今&#xff0c;各种各样的APP平台到处充斥在我们的日常生活之中&#xff0c;出门有打车软件&#xff0c;吃饭有点外卖软件&#xff0c;看剧有影视软件&#xff0c;打发时间有短视频软件等等。而很多软件基本都需要通过地推网推拉新来营销推广&#xff0c;因此诞生了一个庞大…

OpenWrt One/AP-24.XY 开源路由器发布,OpenWRT与Banana Pi社区合作

OpenWrt One/AP-24.XY 开源路由器 2024 年&#xff0c;OpenWrt 项目将迎来20 周年&#xff01;OpenWrt 开源社区官方通过推出社区自己的第一个完全上游支持的硬件设计来庆祝这一周年纪念日。并与联发科&#xff0c;Banana Pi开源社区紧密合作&#xff0c;共同完成硬件的设计与…

人工智能基础-Python之Pandas库教程

文章目录 前言一、Pandas是什么&#xff1f;二、使用步骤1.引入库2.数据读取2.1 数据类型2.2 数据读取1.常见操作2.txt读取 3.pandas的数据结构3.1 Series1.属性2.创建Series3.查询 3.2 DataFrame1.创建DataFrame 4.查询数据4.1 data.loc 根据行列标签值进行查询1.使用单个labe…

Hive数据类型

1.基本数据类型 示例&#xff1a; -- 创建表并定义列的数据类型 CREATE TABLE data_types_example (tinyint_column TINYINT,smallint_column SMALLINT,int_column INT,bigint_column BIGINT,boolean_column BOOLEAN,float_column FLOAT,double_column DOUBLE,string_column S…