数据库轻松切换:解读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://xiahunao.cn/news/2981695.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

flutter release 报错 Error: SocketException: Failed host lookup:

flutter 的 debug 模式没有任何问题 &#xff0c;打了release 包后一直报下面的错&#xff0c;查了一下是 因为没有网络权限 Error: SocketException: Failed host lookup: yomi-test-aws-sg.yomigame.games (OS Error: No address associated with hostname, errno 7) 按照下…

【Vue】常见的七大属性(描述+案例)

一、前言 最近&#xff0c;因为项目需要自己就去学习了一下Vue的相关知识&#xff0c;自己花了几天&#xff0c;结合官方文档和相应的视频学习了一下Vue,了解了Vue大概的一些属性&#xff0c;方法&#xff0c;特点等。接下来博主会将自己学习的相关内容通过博客的形式进行记录…

python实现钉钉通讯录导出Excel表

Python工具开源专栏 Py0004 python实现钉钉通讯录导出Excel表 Python工具开源专栏前言目录结构部分演示完整代码已在GitHub上开源 前言 需求来源于公司&#xff0c;需要将钉钉通讯录以Excel表的形式导出到本地&#xff0c;方便定期备份。导出的Excel需要处理钉钉用户兼任多部门…

W801学习笔记十一:掌机进阶V3版本之硬件改造

经由前面的笔记&#xff0c;我们打造出了一款游戏掌机。 W801学习笔记十&#xff1a;HLK-W801制作学习机/NES游戏机(总结) 然而&#xff0c;考虑到后续的游戏开发&#xff0c;总是忧心容量不足。故而&#xff0c;在正式展开软件开发工作以前&#xff0c;最终进行一下升级改造…

Ai终端程序推荐waveterm

有没有人根据Ai的风口&#xff0c;做智能终端呢&#xff1f;答案是真有&#xff0c;真有专为无缝工作流程而构建的开源 AI 原生终端。它是去年推出的一个产品&#xff0c;专为程序员和开发者设计&#xff0c;比较创新的一点是所有的工作可以在终端完成&#xff0c;开源和可扩展…

Python静态资源库之webassets使用详解

概要 Python webassets库是一个用于管理静态资源的工具,如CSS、JavaScript等,帮助开发者更有效地管理和优化网站的静态文件。本文将介绍如何安装和使用Python webassets库,以及它的特性、基本功能、高级功能、实际应用场景和总结部分。 安装 首先,需要安装Python webasse…

<前端>Electron-builder为公证后的app打更新信息latest.yml

MacOS下&#xff0c;Electron-builder可以很方便的为测试包app打更新信息&#xff08;latest-mac.yml&#xff09;。 但是&#xff0c;正式发布的时候&#xff0c;不可能用测试包app&#xff0c;因为还没有进行公证。如何为公证的app打latest-mac.yml呢。 其实观察latest-mac.y…

StartAI智能绘图软件出现“缺少Python运行库”怎么办?

StartAI做为一款国产AI界的新秀&#xff0c;是一款贴合AIGC新手的智能绘图软件。新手安装遇见“缺少Python运行库”怎么办”&#xff1f;小编一招搞定~ 解决方法&#xff1a;手动下载【resource文件】&#xff0c;将文件添加到安装目录下。 点击链接进行手动下载噢~ 确保 Star…

Pytest精通指南(28)钩子函数-测试报告(pytest-html)

文章目录 前言应用场景插件安装参数分析使用方法拓展-定制化报告 前言 在软件开发过程中&#xff0c;测试是确保代码质量的关键环节。 而测试报告则是测试过程中不可或缺的输出物&#xff0c;它为我们提供了关于测试用例执行情况的详细信息&#xff0c;帮助我们快速定位和解决问…

AGON爱攻×保时捷设计第三代OLED超宽屏PD49震撼上市!

一次科技与艺术的审美共振&#xff0c;开启多维度、沉浸式感官之旅&#xff01; 科技与艺术的融合&#xff0c;引领着美学新时代。4月22日&#xff0c;全球电竞显示器销量冠军品牌AGON爱攻与欧洲最具创造力的设计工作室保时捷设计再度携手&#xff0c;重磅推出AGON爱攻保时捷设…

比亚迪唐EV和唐DM-p荣耀版上市,成为新能源汽车市场中的佼佼者!

随着环保理念的深入人心&#xff0c;新能源汽车市场正迎来前所未有的发展机遇。在这个变革的浪潮中&#xff0c;唐EV和唐DM-p荣耀版的上市无疑为市场注入了新的活力。它们凭借先进的技术、卓越的性能以及豪华配置&#xff0c;成为了新能源汽车市场中的佼佼者。然而&#xff0c;…

数据结构(七)---树

目录 一.树的基本概念 二.树的性质 三.二叉树 1.二叉树的基本概念 2.特殊的二叉树 &#xff08;1&#xff09;满二叉树 &#xff08;2&#xff09;完全二叉树 &#xff08;3&#xff09;二叉排序树 &#xff08;4&#xff09;平衡二叉树 3.二叉树的性质 4.完全二叉树…

Maven:配置与使用指南1

https://mvnrepository.com Maven 1.maven简介 不同模块的jar包以及同时设计的功能的微小变化版本&#xff1b; 真实的开发环境&#xff1a;我们将我们的源代码在服务器上重新编译重新打包&#xff0c;工程升级维护过程繁琐 1.Maven是一个项目管理工具&#xff0c;将项目开…

WebSocket的原理、作用、API、常见注解和生命周期的简单介绍,附带SpringBoot示例

文章目录 原理作用客户端 API服务端 API生命周期常见注解SpringBoot示例 WebSocket是一种 通信协议 &#xff0c;它在 客户端和服务器之间建立了一个双向通信的网络连接 。WebSocket是一种基于TCP连接上进行 全双工通信 的 协议 。 WebSocket允许客户端和服务器在 单个TCP连接上…

【音视频服务】VoIP 推送转 APNs 推送如何设置?

融云控制台 VoIP 设置入口&#xff1a; VoIP 设置 功能说明 针对苹果官方要求收到 VoIP 推送后必须通知给系统 CallKit 框架&#xff0c;如果收到 VoIP 推送后没有报告给 CallKit&#xff0c;iOS 将终止该应用程序&#xff08;目前只影响用 Xcode 11 打包的 App 运行在 iOS 13 …

Springboot实现国际化以及部署Linux不生效问题

1、在application.properties 添加以下配置&#xff1a; #国际化配置 spring.messages.basenamei18n/messages/messages spring.messages.fallback-to-system-localefalse 2、添加配置文件在 resources目录下 如下图所示&#xff1a; 这个国际化文件命名有个坑&#xff0c;必须…

伙伴匹配(后端)-- 前端初始化

文章目录 用脚手架初始化项目安装依赖启动项目image.png整合组件库Vant 用脚手架初始化项目 Vite官网&#xff1a;https://www.vitejs.net/guide/#scaffolding-your-first-vite-project cmd切换到项目目录下初始化项目 npm init vitelatest安装依赖 npm install启动项目 整…

Axure实现tab页面切换功能

1. 实现效果 2. 实现原理 创建两个标签&#xff0c;并实现点击时选中状态点击时&#xff0c;设置面板状态 3. 实现步骤 3.1 实现可切换的标签 在页面上拖拽两个矩形作为两个tab标签&#xff0c;并命名 tab1 和 tab2 设置每个矩形的边框显示&#xff0c;只显示下边框即可 …

2万字长文:Docker必知必会系列

安装docker 安装&#xff1a; Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 **Docker CE 分为 **stable&grav…

Python | Leetcode Python题解之第46题全排列

题目&#xff1a; 题解&#xff1a; class Solution:def permute(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""def backtrack(first 0):# 所有数都填完了if first n: res.append(nums[:])for i in range(first, n):# 动…