数据库轻松切换:解读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 {

  @Override
  protected 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.mfbz.cn/a/567426.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鬼手剪辑如何导入剪映草稿箱?含工程文件

鬼手剪辑导入剪映功能介绍 功能概述 鬼手剪辑导入剪映功能可以让您将鬼手剪辑翻译、克隆和一键解说等作品的工程文件导入到剪映草稿&#xff0c;以便通过剪映进行精细化调整。 推荐使用场景 视频二创 视频语音翻译 短剧解说等作品的微调 导出的工程文件包含以下元素 视频…

windows10小皮安装不同版本composer,实现自由切换使用

1、使用phpstudy小皮面板安装composer1.8.5和composer2.5.8两个版本&#xff1b; 2、打开刚才安装的composer安装目录&#xff1a;D:\phpstudy_pro\Extensions 3、打开composer1.8.5版本&#xff0c;修改composer.bat名称为composer1.8.5.bat&#xff1a; 4、打开composer2.5.8…

uniapp制作多选下拉框和富文本(短信页面)

实例 多选下拉框实现 http://t.csdnimg.cn/TNmcF 富文本实现 http://t.csdnimg.cn/Ei1iV

图解《图搜索算法》及代码实现

关注我&#xff0c;持续分享逻辑思维&管理思维&#xff1b; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导&#xff1b; 有意找工作的同学&#xff0c;请参考博主的原创&#xff1a;《面试官心得--面试前应该如何准备》&#xff0c;《面试官心得--面试时如何进行自…

STM32F4使用FPU/DSP核心启用与测试

STEP1、下载DSP库 具体链接如下&#xff1a; https://www.st.com/en/embedded-software/stsw-stm32065.html?dl9w6sdOSAKySFxBhN764Stg%3D%3D%2CIS1vzyA84KLAefK%2B0DawUl0FScREpiT6AdC3qFjIMJnCIgXIwr82G2XUFo6w43Wp5L5CUyrX3vZAoaHRE3nsTmRsArV3hnQOEgX73SKt8ss1vGrLlfXT24j…

indexDB 大图缓存

背景 最近在项目中遇到了一个问题&#xff1a;由于大屏背景图加载速度过慢&#xff0c;导致页面黑屏时间过长&#xff0c;影响了用户的体验。从下图可以看出加载耗时将近一分钟 IndexDB 主要的想法就是利用indexDB去做缓存&#xff0c;优化加载速度&#xff1b;在这之前&am…

VNISEdit 制作安装包

1. 环境依赖 1.1. NSIS 下载 下载地址&#xff1a;https://nsis.sourceforge.io/Download 1.2. VNISEdit 下载 下载地址1&#xff1a;https://sourceforge.net/projects/hmne/ 下载 exe 安装。 下载地址2&#xff1a;https://hmne.sourceforge.net/ 可以下载 exe 安装。也…

基础算法---前缀和

文章目录 基本思想1.前缀和2.子矩阵的和3.长度最小的子数组4&#xff0c;除自身以外数组的乘积总结 基本思想 前缀和数组就是一个数组的前i项和 前缀和的用处&#xff1a;前缀和数组求出来之后我们就可以就可以求数组中的某个特定区间的和 就比如说求l到R的和&#xff0c;我…

linux休眠唤醒流程,及示例分析

休眠流程 应用层通过echo mem > /sys/power/state写入休眠状态&#xff0c;给一张大概流程图 这个操作对应在kernel/power/main.c的state这个attr的store操作 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n) …

网站想实现HTTPS访问需要有哪些步骤?

网站要实现HTTPS访问&#xff0c;以确保数据传输安全和提升用户信任度&#xff0c;主要需按以下步骤操作&#xff1a; 1. 购买或申请SSL证书&#xff1a; - 根据网站类型和需求&#xff0c;选择合适的SSL证书&#xff1a;DV&#xff08;域名验证&#xff09;、OV&#xff08;组…

Maxwell安装使用和简单案例

一、解压 cd /opt/software/ ​ tar -zxvf maxwell-1.29.2.tar.gz -C /opt/module/ ​ cd /opt/module/ 二、MySQL 环境准备 1、修改 mysql 的配置文件 修改 mysql 的配置文件&#xff0c;开启 MySQL Binlog 设置 vi /etc/my.cnf 添加以下内容 server_id1 log-binmysql-…

冈萨雷斯数字图像处理资源(课后习题答案+代码+图片)

冈萨雷斯数字图像处理相关资源整理&#xff0c;资源全部来源互联网&#xff0c;方便大家下载 冈萨雷斯数字图像处理相关资源整理 课后习题 冈萨雷斯数字图像处理源代码

etcd campaign

1. 引言 本文主要讲解使用etcd进行选举的流程&#xff0c;以及对应的缺陷和使用场景 2. etcd选举流程 流程如以代码所示&#xff0c;流程为&#xff1a; clientv3.New 创建client与etcd server建立连接 concurrency.NewSession 创建选举的session&#xff0c;一般会配置ses…

微信小程序一到六章总结

第一章总结 认识微信小程序 小程序简介 微信(WeChat) 是腾讯公司于2011年1月21 日推出的一款为智能终端提供即时通信服务的应用程序。 小程序、订阅号、服务号、企业微信&#xff08;企业号&#xff09;属于微信公众平台的四大生态体系&#xff0c;它们面向不同的用户群体&…

Harmony OS应用开发性能优化全面指南

优化应用性能对于应用开发至关重要。通过高性能编程、减少丢帧卡顿、提升应用启动和响应速度&#xff0c;可以有效提升用户体验。本文将介绍一些优化应用性能的方法&#xff0c;以及常用的性能调优工具。 ArkTS高性能编程 为了提升代码执行速度&#xff0c;进而提升应用整体性…

若依如何去掉“正在加载系统资源,请耐心等待”

最近有网友反馈这个加载动画很丑&#xff0c;问我如何去掉&#xff1a; 首先找到前端页面的index.html文件&#xff0c;去掉或注释掉如下代码&#xff1a;

使用Gitee进行社交登录的流程

使用Gitee进行社交登录 创建Gitee第三方应用流程&#xff1a; 鼠标移动到个人头像上&#xff0c;点击账号设置 点击账号设置&#xff0c;选择左边目录下数据管理的第三方应用 然后选择创建应用 根据要求填写 填写好了上面的要求之后&#xff0c;点击创建应用&#xff0c;这样&…

【Java】如何获取客户端IP地址

在项目中往往涉及到“获取客户端IP地址”&#xff0c;常见到下面这样子的代码&#xff1a; package com.utils;import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.http.server.reactive.ServerHttpRequest; import java.net…

前端JS必用工具【js-tool-big-box】,获取浏览器参数、cookie、localStorage的存取

这一小节&#xff0c;我们针对js-tool-big-box工具做一些使用讲解&#xff0c;主要获取浏览器参数、cookie、localStorage的存取方面的。 这些方法差不多每次项目中要么用不到&#xff0c;要么就自己写一份&#xff0c;轮子造的很重复啊&#xff0c;而且localStorage有时候要求…

牛客网:环形链表的约瑟夫问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;每日一练 &#x1f337;追光的人&#xff0c;终会万丈光芒 目录 &#x1f3dd;1.问题描述&#xff1a; &#x1f3dd;2.实现代码&#xff1a; &#x1f3dd;1.问题描述&#xff1a; 前言&am…