详谈分布式事务
目录
前言
1.sharding的分布式事务
2.分布式事务的产生原因
3.分布式事务的解决方案
3.1.DTP模型
3.2.分阶段提交
3.3.TCC模式
3.4.可靠消息服务
3.5.AT模式
3.6.Seata
前言
本文是前面一篇文章聊了基于sharding的分库分表后拓展出来的关于分布式事务的讨论,本文中将详细讲一下sharding中的分布式事务以及市面上常见的分布式事务解决方案。
1.sharding的分布式事务
-
Sharding JDBC: Sharding JDBC 提供了对分布式事务的支持。它通过两阶段提交(2PC)协议来实现跨多个数据源的分布式事务。Sharding JDBC 会将事务中的操作发送到各个数据源执行,并在提交阶段协调所有数据源的提交操作,以保证事务的一致性。
-
Sharding Proxy: Sharding Proxy 本身并不直接支持分布式事务。它主要是一个中间件,负责路由和转发客户端的 SQL 请求到后端的多个数据源。在 Sharding Proxy 中,跨多个数据源的事务操作会被拆分成多个独立的本地事务,每个数据源独立处理。这就意味着在 Sharding Proxy 中,跨多个数据源的事务并不会保证全局的一致性,需要应用程序自行处理分布式事务的逻辑。
sharing jdbc后在spring boot中如何使用分布式事务,代码示例:
@Service
public class MyService {
@Autowiredprivate JdbcTemplate jdbcTemplate;
@Transactionalpublic void performDistributedTransaction() {// 在事务范围内执行数据库操作jdbcTemplate.update("INSERT INTO table1 (column1) VALUES (?)", "value1");jdbcTemplate.update("INSERT INTO table2 (column1) VALUES (?)", "value2");// 手动抛出异常,模拟事务中的异常情况throw new RuntimeException("Simulated exception");}
}
是的你没看错,不用任何额外的配置,就是用spring的事务即可。因为sharding jdbc作为一个分库分表的技术栈,天生就有分布式事务问题,所以其默认就是开启分布式事务的,它的事务都是两阶段提交的。
说到分布式事务,我们来回顾一下之前聊过的分布式事务的内容。
2.分布式事务的产生原因
分布式事务是指在在分布式架构下一个事务中的不同子操作是在不同机器上执行的,子操作之间状态无法相互感知,其中有子操作出错后其他机器上的子操作无法正确回滚。
分布式事务产生的根本原因:各个服务之间无感知
举一个例子:
一个下单事务,包含创建订单,库存服务,需要顺序调用订单服务、库存服务。如果库存服务挂掉后,订单服务也是无法回滚的,因为订单服务感知不到库存服务是否成功,即无法感知到库存服务的状态。

3.分布式事务的解决方案
3.1.DTP模型
1994年,X/Open组织(即现在的Open Group)定义了分布式事务处理的DTP模型,该模型包括几个角色:
- 应用程序(AP),服务
- 事务管理器(TM),全局事务管理者
- 资源管理器(RM),一般是数据库
- 通信资源管理器(CRM),TM和RM之间的通信中间件
DTP模型中,一个分布式事务(全局事务)可以被拆分成多个本地事务,运行在不同的AP和和RM上。每个本地事务的ACID由自身保证,全局事务必须保证每个本地事务必须同时成功,若有一个失败其他事务必须回滚。由于本地事务之间相互是无法感知状态的,因此要通过CRM来通知各个本地事务,同步事务执行的状态。
由于各个本地事务之间需要通信,通信就需要标准,因此配套提出了XA通信标准。XA规定了DTP中CRM和TM之间的通信的接口规范,定义了用于通知事务开始、提交、终止、回滚等接口,各个数据库厂商之间必须实现该接口。
3.2.分阶段提交
分阶段提交,也叫两阶段提交(two-phase commit)。DTP模型落地实现的一种思想。
两阶段提交中,将事务分成两个阶段来执行:
- 阶段一,准备阶段,各个本地事务执行自己事务内的逻辑,完成提交前的准备工作。
- 阶段二,执行阶段,各个事务根据上一阶段的执行结果,进行提交或者回滚。
两阶段提交中有两个角色,协调者(coordinator)、参与者(voter)。
正常情况:

异常情况:
准备阶段协调者会询问每个参与者是否可以执行事务,每个事务参与者执行事务写入redo、undo日志,然后反馈事务的执行结果,只要有一个参与者返回的是disagree则说明失败,协调者会像各个参与者发出abort指令,各个事务收到指令后各自回滚事务。

两阶段提交的优点:
- 方案成熟,很稳
- 能保证强一致性
两阶段提交的缺点:
- 单点故障,当协调者挂了之后后续的步骤就没办法进行了,被锁住的数据没办法解锁,会造成阻塞。
- 数据锁定,分阶段提交由于过程被拆成两段,会造成本地事务的执行过程变长,数据会长时间处于锁定状态。
3.3.TCC模式
TCC模式是专门用来解决分阶段提交的缺陷的,减少数据锁定,避免阻塞问题。
TCC相当于是强化了两阶段提交,在分阶段提交中埋入了以下几个点位:
- try,资源的检测和预留。
- confirm,执行的业务操作提交,要求try成功的话confrim一定要能成功。
- cancel,预留资源释放
经过TCC的强化埋点后两阶段提交变成了:
- 准备阶段。try,资源预留,通知每个参与者去try一下数据资源,判断一下数据资源是否足以支撑之后的事务运行。每个参与者均try成功再执行下一步,否则直接cancel。
- 执行阶段,confrim,让协调者通知各个参与者执行并提交事务(因为资源已经准备好了,执行和提交可以一气呵成),各个参与者confrim成功则成功,但凡有一个失败则通知协调者组织全局回滚、释放资源、退出。

TCC的优点:
TCC其实每个阶段都是单独的事务,try其实是个事务只是去摸一下看下阶段要的数据资源是否能用,confrim则是原来的包含业务逻辑的事务。这样的话就避免了两阶段提交中agree过程中对于数据的锁定,尽量避免了影响其他事务的执行。
TCC的缺点:
- 编码成本,存在代码侵入需要开发人员手动编写TCC三步,开发的成本会比较高。
- 弱一致性,TCC保证的是最终一致性,因为单个本地事务的执行和提交都包含在confirm一个步骤中,如果出现问题回滚前其实是没有保证一致性的,在这中间有其他读操作进来是能读到已经变动的数据的。
3.4.可靠消息服务
可靠消息服务起源自eBay,是将各个服务的本地事务串成一个链,依托MQ来保障分布式事务,比如服务A执行完服务后向MQ中存放自己执行成功的信息,MQ再向服务B推送消息叫它执行本地事务,服务B执行完本地事务后又告诉MQ,MQ继续向后续要执行本地事务的服务推送消息。

缺点:
由于是MQ主动向后续服务推送消息,后续服务要是失败了,前置服务感知不到,前置服务无法进行感知回滚。。所以可靠消息服务适用的场景有限。
3.5.AT模式
AT模式是Alibaba的seata组件开源出来的一种分布式事务解决方案,是对TCC的一种优化,解决了TCC模式中的的代码侵入、编码复杂等问题。
AT模式中,用户只需关注自己的业务SQL,seata框架会自动生成书屋的二阶段提交和回滚操作。
AT模式整个流程和TCC大致相同,不同点是在于AT模式将执行放在了一阶段:
- 一阶段(开发者实现),正常编写业务逻辑,然后执行SQL,执行本地事务,并返回执行结果。
- 二阶段(框架托管),根据一阶段的结果判断二阶段的做法,提交或者回滚。
AT模式的底层原理:

在阶段一的时候拦截下所有SQL,框架会去解析这条SQL然后去数据库中查询出要操作的数据,存一份镜像叫before image,接下来执行SQL,执行完SQL后再查询一次,存一份叫after image。
到了阶段二的时候,比对before镜像和after镜像从而判断操作是否成功,如果一阶段的所有本地事务操作都是成功的,就会清空before镜像和after镜像,如果有一个是失败的各个本地事务就会根据属于自己的before镜像进行回滚。
after镜像是为了在回滚的时候进行比对,要是回滚时发现数据库中此时的数据和after镜像中记录的数据不相同,则说明数据又被动过了,产生了脏数据,此时就需要人工介入了。由于行锁的存在,产生脏数据的概率很低很低,after镜像只是留了一手。
AT模式中的角色:

AT模式中一共有三个角色
- TC,服务协调者,是一个单独的服务。
- TM,通信中间件。
- RM,资源管理器,管理分支的事务处理,与TC进行通信注册分支事务和报告事务状态,驱动分支事务提交或者回滚。
TM、RM和服务是耦合在一起的,但是不侵入代码,以jar包的方式体现。
3.6.Seata
Seata是目前为止常用、流行切稳定的分布式事务解决方案,其在使用上对代码没有侵入,直接是基于配置的,使用方法见官方手册即可。在遇到分布式事务场景时,可以优先考虑使用seata来解决。
相关文章:
详谈分布式事务
目录 前言 1.sharding的分布式事务 2.分布式事务的产生原因 3.分布式事务的解决方案 3.1.DTP模型 3.2.分阶段提交 3.3.TCC模式 3.4.可靠消息服务 3.5.AT模式 3.6.Seata 前言 本文是前面一篇文章聊了基于sharding的分库分表后拓展出来的关于分布式事务的讨论…...
Java基础知识八股
1.为什么静态方法无法调用非静态方法? 回答:因为静态方法是随着类的加载而加载,而非静态方法则是随着类的实例化才会被加载,生存周期不一样,所以静态方法的生命周期更长 2.Java–内部类持有外部类导致内存泄露的原因和…...
【Linux】网络基础一
网络基础一 1.计算机网络背景1.1 网络发展1.2 认识 “协议” 2.网络协议初识2.1 协议分层2.2 OSI七层模型2.3 TCP/IP五层(或四层)模型 3. 网络传输基本流程3.1 网络传输流程图 4.数据包封装和分用5.网络中的地址管理 从今天开始我们将要从系统横跨到网络的学习了,因…...
Redis-2 Redis基础数据类型与基本使用
高级Redis应用进阶 一站式Redis解决方案-Redis-2 Redis基础数据类型与基本使用 源代码在GitHub - 629y/food-social-contact-parent: redis项目-美食社交APP 1. Redis基本数据类型 1.字符串(strings) set username zhangsan get username mset age 18 …...
python提取身份证中的生日和性别
1.代码 def sfzAnalysis(idNum):#检查身份证长度是否正确if len(idNum)!18:raise ValueError("身份证号码长度不正确,请输入一个18位的身份证号码。")#raise关键字在Python中有多种用途,主要涉及异常的抛出和错误处理#提取出生日期year idN…...
opencv 傅里叶变换(低通滤波 + 高通滤波)
文章目录 1、傅里叶变换2、通过numpy实现3、高通滤波器5、通过opencv实现傅里叶变换6、低通滤波器7、C实现傅里叶变换 1、傅里叶变换 时域分析:以时间作为参照物,世间万物都是随着时间变化而变化,并且不会停止 频域分析:认为世间万…...
Educational Codeforces Round 163 (Rated for Div. 2)(A,B,C,D,E)
比赛链接 好忙好忙好忙,慢慢补老比赛的题解了。 这场没啥算法,全是思维。有也是BFS,屎。 A. Special Characters 题意: 您将得到一个整数 n n n 。 您的任务是构建一串大写的拉丁字母。此字符串中必须正好有 n n n 个特殊字…...
索引常见面试题
面试中,MySQL 索引相关的问题基本都是一系列问题,都是先从索引的基本原理,再到索引的使用场景,比如: 索引底层使用了什么数据结构和算法?为什么 MySQL InnoDB 选择 Btree 作为索引的数据结构?什…...
【Unity】旋转的尽头是使用四元数让物体旋转
// 导入必要的命名空间 using System.Collections; using System.Collections.Generic; using UnityEngine;// 创建一个名为 RotateObj 的 MonoBehaviour 类,该类可以附加到 Unity 中的游戏对象上并控制其行为 public class RotateObj : MonoBehaviour {// Update 函…...
哔哩哔哩秋招Java二面
前言 作者:晓宜 个人简介:互联网大厂Java准入职,阿里云专家博主,csdn后端优质创作者,算法爱好者 一面过后面试官叫我别走,然后就直接二面,二面比较简短,记录一下,希望可以…...
OSPF特殊区域(stub\nssa)
stub区域——只有1类、2类、3类;完全stub区域——只有1类、2类 NSSA区域:本区域将自己引入的外部路由发布给其他区域,但不需要接收其他区域的路由 在NSSA区域的路由器上,引入外部路由时,不会转换成5类LSA,…...
全球首位AI程序员诞生,将会对程序员的影响有多大?
随着全球首位AI程序员Devin的诞生,人工智能技术在编程领域的应用引发了广泛的讨论和思考。这一事件不仅标志着AI技术在软件开发领域的一大步进展,也引起了人们对未来编程职业发展的广泛关注。那么,AI程序员的出现究竟会对程序员的职业生涯产生…...
【晴问算法】提高篇—动态规划专题—最长上升子序列
题目描述 现有一个整数序列a1,a2,...,an,求最长的子序列(可以不连续),使得这个子序列中的元素是非递减的。输出该最大长度。 输入描述 第一行一个正整数n(1≤n≤100),表示序…...
天软特色因子看板(2024.3第5期)
该因子看板跟踪天软特色因子A08006(近一月日度买卖压力2),该因子为近一个月个股每日的相对价格位置,用以刻画股票所受买卖压力,取作 介于0~1间,指标值越大,反映股票在价格相对高位停留的时间越长,所面临的买…...
静态网络配置
一、查看网络命令 1.命令行查看网络配置 1、查看ip\硬件设备-网卡 ifconfig -a ifconfig ens160 网卡名称 ip addr show ip addr show ens160 nmcli device show ens160 nmcli con up ens160 2、主机名称 hostname hostname hfj.huaxia.com 3、查看路由和网关 rou…...
多种智能搜索算法可视化还原 3D 魔方
2024/03/19:程序更新说明(文末程序下载链接已更新) 版本:v1.0 → v1.2 ① 修复:将 CLOSED 表内容从优先级队列中分离开来,原优先级队列作 OPEN 表,并用链表树隐式地代替 CLOSED 表,以…...
Maven,pom.xml,查找 子jar包
在IDEA打开pom.xml,会看到这里: 然后如果有需要,把相关的 子jar包 去掉 <dependency><groupId>XXX</groupId><artifactId>XXX</artifactId><exclusions><exclusion><artifactId>xxx</a…...
MySQL中数据库表的监控
MySQL中数据库表的监控 (1)查看数据库中当前打开了哪些表:show OPEN TABLES ,如图6-1-5所示。另外,还可以通过show OPEN TABLES where In_use > 0过滤出当前已经被锁定的表。 查看数据库中表的状态:SHO…...
【S5PV210_视频编解码项目】裸机开发2:实现PWM波形驱动蜂鸣器
开发内容介绍 基于芯片自带的PWM定时器模块,实现对PWM波形的控制,掌握pwm定时器的驱动程序开发。 开发理论架构 1)pwm波形的产生的条件:在指定的IO口输出一定频率和占空比的波形 2)pwm波形频率的影响因素࿱…...
js进阶-深入对象-内置构造函数-包装类
一. 创建对象的三种方式 1.1 利用对象字面量创建对象 const p {name:"kebi" }1.2 利用 new Object 创建对象 // const obj new Object()// obj.uname maidi// console.log(obj)const obj new Object({ uname: maidi })1.3 利用构造函数创建对象 大写字母开头的…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
