DynamicDataSource是如何解决多数据源的事务问题?

2023-11-08

多数据源的真面目DynamicRoutingDataSource

DynamicRoutingDataSource是什么?

该类实现了DataSource接口并在内部维护了一个map,其中存放了多个真实的DataSource,而key则是不同数据源的名称,本质上就是基于静态代理模式代理了多个真实的数据源对象

在用多数据源时可以使用@DS来切换不同的数据源,这依赖于DynamicRoutingDataSource。要完成这个功能需要@DS+DSProcessor+ThreadLocal+AopMethodInterceptor+DynamicRoutingDataSource#getConnection相互配合才能成功切换数据源。

多数据源下的事务会有什么问题?

在没有多数据源时,系统中一般只会存在一个Datasource,所谓的HikariDataSource,DruidDatasourceCommonsDbcp2PoolDataSource都是DataSource的实现,但是在系统中总是唯一存在的。因为SqlSessionTemplateFactory中只能存在一个DataSource,SqlSessionTemplate又是通过SqlSessionTemplateFactory生成的,并且SqlSessionTemplate在容器中又只能存在一个,所以事务时不会出现混乱的。而DynamicRoutingDataSource同样也是系统中的唯一的Datasource,只不过它内部代理了多个DataSource。

再来说说spring的事务管理器TransactionSynchronizationManager,内部使用ThreadLocal保存当前事务信息。当程序执行到@Transactional的AOP拦截器时,会在ThreadLocal中保存当前的事务信息,其中就包含了与数据库的Connection对象。在程序执行sql时,spring的SqlSessionTemplate#getSession方法会从事务管理器中获取到与当前线程绑定的connection对象。

综上所述,当使用@DS切换数据源时,没有事务的情况下还好,会使用DynamicRoutingDataSource获取一个新的connection并使用,但是如果是在事务的情况下,会使用事务管理器中获取与当前线程绑定的Connection,而这个connection则是事务被创建时获取的connection,就造成了虽然指定了数据源,但是还是原本的那个connection。导致切换数据源失败。

@Ds与@DsTransactional

通过观察DynamicDataSourceAutoConfiguration自动配置类可以发现,DynamicDataSource默认自动配置了@Ds注解@DsTransactional注解的切面。分别是dynamicDatasourceAnnotationAdvisordynamicTransactionAdvisor

@Ds的原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其切面方法拦截器会将指定的ds名称存入DynamicDataSourceContextHolder中的ThreadLocal<Deque<String>>中,因为指定了ThreadLocalMap的泛型为Deque,而Deque的作用更准确的说是栈的作用,所以支持方法嵌套调用时使用不同的ds名称。

@DsTransactional的原理

在这里插入图片描述
通过源码可以发现在没有使用seta分布式事务控制的情况下,多数据源的事务是通过dynamicDatasourceAnnotationAdvisor管理的。
dynamicDatasourceAnnotationAdvisor的核心切面拦截器就是DynamicLocalTransactionInterceptor

DynamicLocalTransactionInterceptor多数据源本地事务拦截器

内部实现原理非常简单,其实就是借助于ThreadLocal。
在这里插入图片描述
在这里插入图片描述
看到这里,你可能已经猜到了,面纱下面的真面目就是这个ConnectionFactory类了。我们再来看看他张了一幅什么面貌。
在这里插入图片描述
在这里插入图片描述

我们已经知道了notify方法是@DsTransactional切面环绕通知结束时会被调用的,本着追溯本源的好奇心,你可能开始好奇了,putConnection又是什么时候被调用的呢?我们继续跟进就来到了AbstractRoutingDataSource。 好!又回到了DynamicRoutingDataSource中, AbstractRoutingDataSource就是DynamicRoutingDataSource父类。
在这里插入图片描述
在这里插入图片描述
在本地事务结束时,TransactionContext会清空本地事物的状态标识,然后分别结束每一个connection的事务状态。然后清除ConnectionFactory中保存的与本次本地事物有关的所有connection对象的引用。

至此本地事物的创建和结束就完成了闭环。

总结一下多数据源事务的控制中,参与的核心职责类有哪些

  • DynamicRoutingDataSource: DataSource接口的实现,也是一个DataSource,本质是多个DataSource的静态代理类。自定义了getConnection方法的实现逻辑,使其与多数据源的事务管理紧密配合。
  • TransactionContext:使用ThreadLocal实现。本地事物上下文。负责管理本地事物的状态。
  • ConnectionFactory: 使用ThreadLocal实现。connection连接的静态代理类,也是一个委派者设计模式。负责管理当前本地事务中的所有Connection。
  • ConnectionProxy: 封装了真实的Connection。 目的是将ds数据源名称和connection对应起来,这样可以通过ds数据源名称拿到对应的connection。
  • @Ds:用于指定接下来要使用的数据源名称。
  • @DsTransactional: 多数据源事务的开启注解,用法同@Transactional相同。但是不能指定事务的一些属性,因为其实现的原理,也不需要任何其他的事务的配置。当发生任何Exception时都会执行回滚
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DynamicDataSource是如何解决多数据源的事务问题? 的相关文章

随机推荐

  • Spring Boot 整合各种常用技术的代码都在这了

    文章目录 前言 技术清单 简要说明 代码地址 交流 前言 一份慕课网价值 58 元的专栏课程 Spring Boot 趣味私房课 源码 内容为 Spring Boot 与当今主流技术的整合 有很多使用的范例 技术清单 Swagger JUn
  • 老主板BIOS不识别nvem固态硬盘,修改BIOS添加nvme驱动

    以我的技嘉ga f2a68hm s1主板为例 提前到技嘉官网GIGABYTE 技嘉科技下载好对应的BIOS 版本 1 到主板的官方 2 输入主板型号 点击 搜索 3 下载BIOS包 正题开始了 1 准备工具 MMTOOL 2 4GB以上U盘
  • 卡方检验的基本思想是比较实际观察到的频数与期望的频数之间的差异

    卡方检验 Chi Square Test 是一种用于分析分类数据之间的关联性或独立性的统计方法 它通过比较观察到的数据与预期的数据之间的差异来判断两个或多个变量之间是否存在关联 卡方检验通常用于交叉表格 列联表 的分析 例如 研究两种分类变
  • 用java和c++写一个vpn实例的思路

    1 C 开发VPN核心模块 支持更多VPN类型 cpp PPTPContext cpp SSL CTX createPPTPContext PPTPSocket cpp class PPTPSocket public PPTPSocket
  • tolua 判断对象是否为空

    https blog csdn net baidu 39447417 article details 80001371
  • Redis BitMap结构实现签到、连续签到统计

    文章目录 一 利用BitMap结构实现签到功能 1 1 BitMap用法 1 2 代码实现签到功能 1 3 统计连续签到 1 3 1 如何得到本月到今天为止的所有签到数据 1 3 2 如何从后向前遍历每个bit位 1 3 3 代码实现 一
  • 【线代】矩阵的特征值与特征向量原理详解

    如果把矩阵看作是运动 对于运动而言 最重要的当然就是运动的速度和方向 特征值就是运动的速度 特征向量就是运动的方向 参考链接 https www zhihu com question 21874816 answer 181864044 因为
  • 简单的介绍

    最近没有怎么发博客 也不能说自己没有学习 嘿嘿嘿 自己最近在学习框架和java 也很少做ctf 然后把一些学习的产出放在了知识星球或者是github上 想需要一个东西来管理一下 因为自己太懒了 没有搭建个人博客 我还是会发一些我感觉重要的东
  • 算法训练 星际交流

    ALGO 28 星际交流 资源限制 时间限制 1 0s 内存限制 256 0MB 问题描述 人类终于登上了火星的土地并且见到了神秘的火星人 人类和火星人都无法理解对方的语言 但是我们的科学家发明了一种用数字交流的方法 这种交流方法是这样 的
  • numpy的mgrid[]和ogrid[]

    函数说明 mgrid ogrid
  • C语言中常见的一些语法概念和功能

    常用代码 程序入口 int main 函数用于定义程序的入口点 输出 使用 printf 函数可以在控制台打印输出 输入 使用 scanf 函数可以接收用户的输入 条件判断 使用 if else 语句可以根据条件执行不同的代码块 循环结构
  • python使用sqlalchemy判断数据库是否包含某张表

    代码如下 from sqlalchemy import create engine def table exists engine table name 这个函数用来判断表是否存在 with engine connect as con sq
  • NLP基础知识

    1 熟悉 Python 语言 了解一个深度学习框架 Pytorch Tensorflow 或 MXNet 2 熟悉简单的机器学习模型 如 LR SVM HMM 正则化等 3 熟悉简单的深度学习模型 如 word2vec CNN RNN 目录
  • C++之红黑树

    红黑树 1 概念 红黑树 是一种二叉搜索树 但在每个结点上增加一个存储位表示结点的颜色 可以是Red或Black 通过对任何一条从根到叶子的路径上各个结点着色方式的限制 红黑树确保没有一条路径会比其他路径长出俩倍 因而是接近平衡的 2 性质
  • (转)四元数概念及其应用

    1 采用右手坐标系 OpenGL 2 旋转次序 x gt y gt z 3 矩阵是列优先存储 1 什么是四元数 直接用数学上的定义来解释 因为我很难在现实生活中找到可以描述明白的例子 i j k 为虚数 Q w xi yj zk 其中w是实
  • 图像分类算法—KNN、SVM、BP、CNN

  • Yarn日志过大无法拉取java.lang.RuntimeException: The total log size is too large.The log size limit is 10240M

    yarn拉取日志命令 yarn logs applicationId application 1624172467753 3988 appOwner root size limit mb 1 gt application 162417246
  • 多线程竞争及解决方法

    线程是非独立的 同一个进程里线程的数据是共享的 当各个线程访问数据资源时会出现竞争状态 即 数据几乎同步会被多个线程占用 造成数据混乱 即所谓的线程不安全 解决多线程问题的方法 锁 锁的好处 确保了某段关键代码 共享数据资源 只能有一个线程
  • 树莓派3B+安装Raspbian简易教程

    刚买的树莓派3B 没过一周 树莓派4就出来了 不过算了 基本上用起来差不多 所以大家继续看吧 最近有点忙 所以就不BB了 直接上主题 下载Raspbian Raspbian是树莓派的官方系统 推荐大家使用 如果不喜欢它的话 可以自己安装Ub
  • DynamicDataSource是如何解决多数据源的事务问题?

    多数据源的真面目DynamicRoutingDataSource DynamicRoutingDataSource是什么 该类实现了DataSource接口并在内部维护了一个map 其中存放了多个真实的DataSource 而key则是不同