Springboot 多数据源事务

起因

在一个service方法上使用的事务,其中有方法是调用的多数据源orderDB

image.png
image.png
image.png
image.png

但是多数据源没有生效,而是使用的primaryDB

image.png

原因

spring 事务实现的方式

@Transactional 注解为例 (也可以看 TransactionTemplate, 这个流程更简单一点)。
入口:ProxyTransactionManagementConfiguration
(从 config 类入手,需要哪些bean一目了然,然后直接顺着看下去就可以了)
主要有以下3个bean

  • TransactionAttri``buteSource:实现是 AnnotationTransactionAttributeSource, 提供从(存在 @Transactional 注解的)方法上读取事务的属性(注解的属性)的功能
  • TransactionInterceptor:事务方法拦截器的bean,在执行事务方法时,转到 (TransactionAspectSupport#invokeWithinTransaction) 方法,即spring事务处理的主要逻辑。
  • BeanFactoryTransactionAttributeSourceAdvisor:一个advisor(包含一个 Pointcut 切点和一个 Advice 通知),advice就是上面的事务拦截器,Pointcut 切点匹配能通过 TransactionAttributeSource 获取到事务信息的方法。

拦截器逻辑大概如下:
image.png

解决方案

每个数据源手动配置SqlSessionFactory

这种方式是通过手动声明创建orm框架对应的bean来实现多数据源的操作,即每个数据源都自己手动创建一套对用的bean。
不支持多个数据源事务,手动配置较繁琐
(如果使用的spring而不是springboot的话,就不会有这种多数据源的疑问,因为本来就要自己声明bean)

动态数据源(本次使用)

只需要把@Transactional(rollbackFor = Exception.class) 换为@DSTransactional即可
并且抛出异常事务也会回滚

image.png

动态数据源实现原理

同样看一下 DynamicDataSourceAutoConfiguration 这个配置相关的类就大概了解了。

  • DynamicRoutingDataSource: 动态数据源,内部使用 Map 保存了多个数据源。获取 connection 时,根据 ThreadLocal 中的 dsKey 获取对应的数据源
    • 另:对于多数据源事务 (TransactionContext.getXID() isNotEmpty),会返回一个 ConnectionProxy 并暂存到 ConnectionFactory 中, 该 ConnectionProxy 不会执行 commit、rollback、close 操作事务相关的方法。
public Connection getConnection() throws SQLException {String xid = TransactionContext.getXID();if (StringUtils.isEmpty(xid)) {// 非多数据源事务直接获取对应 connectionreturn determineDataSource().getConnection();} else {String ds = DynamicDataSourceContextHolder.peek();ds = StringUtils.isEmpty(ds) ? "default" : ds;// 多数据源事务,使用代理的 connection (屏蔽了 commit 等操作)ConnectionProxy connection = ConnectionFactory.getConnection(ds);return connection == null ? getConnectionProxy(ds, determineDataSource().getConnection()) : connection;}
}// 获取 代理的 connection, 并将其存入 ConnectionFactory, 内部维护一个 ThreadLocal<Map>, 同时会 setAutoCommit(false) 开启事务
private Connection getConnectionProxy(String ds, Connection connection) {ConnectionProxy connectionProxy = new ConnectionProxy(connection, ds);ConnectionFactory.putConnection(ds, connectionProxy);return connectionProxy;
}// DynamicRoutingDataSource
// 从 ThreadLocal 获取当前 dsKey 然后获取对应 datasource
public DataSource determineDataSource() {String dsKey = DynamicDataSourceContextHolder.peek();return getDataSource(dsKey);
}
  • DynamicDataSourceAnnotationInterceptor: 处理 @DS 注解的拦截器,获取 @DS 指定的 datasource 并存入 ThreadLocal 中, 供 DynamicRoutingDataSource 使用
  • dynamicTransactionAdvisor: 处理 @DSTransactional 多数据源事务注解的拦截器,在执行目标方法前,标记为多数据源事务 (TransactionContext.bind(xid)), 执行完后, 通知 ConnectionFactory 中的 connectionProxy 进行事务的 commit 或 rollback。
// DynamicLocalTransactionAdvisor
public Object invoke(MethodInvocation methodInvocation) throws Throwable {if (!StringUtils.isEmpty(TransactionContext.getXID())) {return methodInvocation.proceed();}// 事务是否成功boolean state = true;Object o;String xid = UUID.randomUUID().toString();// 标记当前为 多数据源事务TransactionContext.bind(xid);try {o = methodInvocation.proceed();} catch (Exception e) {state = false;throw e;} finally {// 通知 connectionProxy 进行 commit 或 rollbackConnectionFactory.notify(state);TransactionContext.remove();}return o;
}

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

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

相关文章

Java语言程序设计——篇九(1)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 内部类 概述内部类—内部类的分类成员内部类实战演练 局部内部类实战演练 匿名内部类实战演练 静态内部类实战演练 概述 内部类或嵌套类&#…

sheng的学习笔记-AI-公式-指数加权移动平均(EWMA)

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 基础知识 指数加权移动平均&#xff08;Exponential Weighted Moving Average&#xff09;&#xff0c;是一种常用的序列处理方式 看例子&#xff0c;首先这是一年365天的温度散点图&#xff0c;以天数为横坐标&#xff0…

【学一点儿前端】本地或jenkins打包报错:getaddrinfo ENOTFOUND registry.nlark.com.

问题 今天jenkins打包一个项目&#xff0c;发现报错了 error An unexpected error occurred: "https://registry.nlark.com/xxxxxxxxxx.tgz: getaddrinfo ENOTFOUND registry.nlark.com". 先写解决方案 把yarn.lock文件里面的registry.nlark.com替换为registry.npmmi…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十八章 中断下文之tasklet

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

全球性“微软蓝屏”事件及其对网络安全和系统稳定性的深远影响

近日&#xff0c;一次由微软视窗系统软件更新引发的全球性“微软蓝屏”事件&#xff0c;不仅成为科技领域的热点新闻&#xff0c;更是一次对全球IT基础设施韧性与安全性的深刻检验。这次事件源于美国电脑安全技术公司“众击”提供的一个带有“缺陷”的软件更新&#xff0c;它如…

女人内裤怎么洗才是最干净?内衣裤洗衣机怎么样?哪个牌子更好?

最近刚好用到一款比较好用的洗内衣裤洗衣机&#xff01;如果你也和我一样有洗内衣裤烦恼的&#xff0c;或者可以看看&#xff01; 内衣裤作为贴身穿的衣服&#xff0c;我是不会把它和外衣一起清洗的&#xff0c;而家里面的大洗衣机已经担起了清洗外衣的工作&#xff01; 朋友们…

JVM 内存分析工具 Memory Analyzer Tool(MAT)入门(一)

一、打开 jvisualvm &#xff08;VisualVM 是一款集成了 JDK 命令行工具和轻量级剖析功能的可视化工具。 设计用于开发和生产。&#xff09; 打开 jvisualvm.exe 工具会出现如下一些监控指标 二、VisualVM可以根据需要安装不同的插件&#xff0c;每个插件的关注点都不同&#x…

uniapp vue3 使用画布分享或者收藏功能

使用HBuilder X 开发小程序&#xff0c;大多数的画布插件很多都是vue2的写法&#xff0c;vue3的很少 我自己也试了很多个插件&#xff0c;但是有一些还是有问题&#xff0c;不好用 海报画板 - DCloud 插件市场 先将插件导入项目中 自己项目亲自用过&#xff0c;功能基本是完善…

谷粒商城-性能压测

1.压力测试 在项目上线前对其进行压力测试(以每个微服务为单元) 目的:找到系统能承载的最大负荷,找到其他测试方法更难发现的错误(两种类型:内存泄漏,并发与同步). 1.性能指标 响应时间(Response Time (RT)): 响应时间 指用户从客户端发起一个请求开始,到客户端接收到从服务…

【第五天】HTTPS和HTTP有哪些区别,HTTPS的工作原理

HTTPS和HTTP的区别&#xff1a; 1.安全性&#xff1a; HTTP是明文传输协议&#xff0c;数据在传输的过程中不加密&#xff0c;容易被窃听和篡改。HTTPS通过使用SSL或TLS协议对数据进行加密&#xff0c;确保传输的数据在网络上是安全的&#xff0c;不容易被窃取和篡改。 2.加…

leetcode-104. 二叉树的最大深度

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,n…

自动化测试 pytest 中 scope 限制 fixture使用范围!

导读 fixture 是 pytest 中一个非常重要的模块&#xff0c;可以让代码更加简洁。 fixture 的 autouse 为 True 可以自动化加载 fixture。 如果不想每条用例执行前都运行初始化方法(可能多个fixture)怎么办&#xff1f;可不可以只运行一次初始化方法&#xff1f; 答&#xf…

一招就能轻松解决猫咪浮毛?最新值得买的浮毛空气净化器汇总分享

那次逛街后去朋友家&#xff0c;她家猫哈基米特别热情&#xff0c;一开门就扑过来&#xff0c;朋友直接给了个大拥抱加亲亲。汗水和猫毛全粘身上了&#xff0c;看着都让人头皮痒。好多铲屎官都抱怨&#xff0c;就算天天梳毛&#xff0c;家里还是到处都是毛&#xff0c;毕竟家里…

理解文件系统(上)

模拟实现文件库 创建文件以便理解 自己想实现的文件接口&#xff0c;进行模拟实现 模拟的头文件要准备的头文件 open接口的实现 write接口的实现fflush接口的实现 flose接口的实现 文件实现 stdio.h stdio.c test.c makefile 创建makefile 编译运行 执行后输出log.txt,看…

【虚拟机】 VMware截图版详细安装教程

VMware-workstation-full-17.5.1-23298084 的安装&#xff0c;详细安装过程。 1.以管理员身份运行安装包 点击文件&#xff0c;右键打开&#xff0c;以管理员身份运行&#xff1b; 2.根据安装提示&#xff0c;重启电脑&#xff1b; &#xff08;重启与否看自己电脑情况&…

【深入理解SpringCloud微服务】深入理解Ribbon原理并手写一个微服务负载均衡器

深入理解Ribbon原理并手写一个微服务负载均衡器 负载均衡器理解Ribbon原理手写一个微服务负载均衡器总体设计LoadBalanceClientHttpRequestFactorySimpleLoadBalanceClientSimpleLoadBalancerLoadBalanceRulespring.factories与LoadBalanceConfig 负载均衡器 在微服务架构里面…

ElasticSearch(七)— 相关性检索和组合查询

一、 相关性评分 全文检索与数据库查询的一个显著区别&#xff0c; 就是它并不一定会根据查询条件 做完全精确的匹配。除了模糊查询以外&#xff0c;全文检索还会根据查询条件给文档的相关性打分并排序&#xff0c;将那些与查询条件相关性高的文档排在最前面。 相关性( Relev…

kubernetes service详解

一、service的类型 clusterip&#xff1a;集群内部访问externalname&#xff1a;调用外部API时使用&#xff0c;域名解析&#xff0c;让应用不用关心实际的IP地址nodeport&#xff1a;集群外部访问&#xff0c;暴漏节点上的端口&#xff0c;转发到pod内loadbalancer&#xff1…

【科大讯飞笔试题汇总】2024-07-27-科大讯飞秋招提前批(研发岗)-三语言题解(Cpp/Java/Python)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新 秋招笔试题 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f4e7; 清隆这边最近正在收集近一年半互联网笔试题汇总&#xff0c;有需要的小伙伴可以关注 文末 公主号…

如何通过压缩提示降低GPT-4的成本

如果使用得当&#xff0c;LLMLingua可以降低使用高级LLM的成本&#xff0c;并使更广泛的用户和应用程序可以使用LLM。 像GPT-4和Claude这样的大型语言模型(LLM)可以通过良好的提示工程学习新任务。然而&#xff0c;较长的提示会增加使用这些模型的成本&#xff0c;并且还会减慢…