【Seata】03 - Seata AT 模式全局锁相关知识简单整理

2023-11-03

前言

上一篇文章介绍了 AT 模式的调用流程,但是有个比较重要的概念没有提及到,所以这一篇来展开说明一下——全局锁。

参考目录

版本说明

由于官方 Demo 版本较低,本文使用的版本如下:

  • SeataV1.7.0
  • druid-spring-boot-starterV1.2.16

分析整理

1、全局锁的引入说明

在官方文档对于 AT 模型的篇章中有进行关于读写隔离的示例说明,这其中就涉及到了全局锁。

(截图自官方文档)在这里插入图片描述

在 Demo 里面业务主要是进行了写隔离,因此下面的分析也是以此为基础进行展开。

上图简明扼要提出了全局锁的获取时机以及应用场景,下面结合源码来看下。

2、全局锁相关源码整理

2.1、流程简图

上篇文章有根据输出记录按照时序步骤绘制了流程图,对关键的信息进行提取后加上全局锁的内容,绘制了新的流程图:

在这里插入图片描述

简单说明一下:

  • 这张简图主要是事务分支相关的操作,因此没有绘制 TM 相关的内容。
  • 虚线方框内是同一个方法的操作。
  • 主要的方法也一并贴出来方便后续查找。

2.2、事务分支注册前的 SQL 相关操作

这一部分在上一篇文章也有提及,这里再简单带过一下。

在分支注册前,回先执行业务逻辑,生成前后镜像,再贴一下堆栈信息图:

在这里插入图片描述

io.seata.rm.datasource.exec.AbstractDMLBaseExecutor#executeAutoCommitFalse

在这里插入图片描述

得到前后镜像是为了生成 UndoLog 方便后续回滚操作。SQL 执行之后还没有 Commit,需要获取到全局锁并且在数据库表中写入 UndoLog 后才会提交。

完成这一步骤之后,继续分支事务操作,方法 io.seata.rm.datasource.ConnectionProxy#processGlobalTransactionCommit 完成了三个重要步骤:

  1. 注册分支(包含获取全局锁)
  2. undo_log 记录插入
  3. SQL 提交

在这里插入图片描述

本文的分析要点集中在步骤 1 中,对于步骤 2 上一篇博客已经进行了详细的分析,也贴出了相关的 UndoLog 内容,本文就不再进行说明。

2.3、注册分支(获取全局锁)

来到 Client 端(RM)注册分支的底层方法:

io.seata.rm.AbstractResourceManager#branchRegister

在这里插入图片描述

来到 Server 端(TC)的分支注册方法:

io.seata.server.coordinator.AbstractCore#branchRegister

在这里插入图片描述

该方法的主要逻辑:

  1. 使用 xid 获取到全局会话。
  2. 锁定会话并在事务上下文进行操作。
  3. 全局会话状态检查。
  4. 全局会话添加会话生命周期监听器。
  5. 新建全局事务分支,获得分支会话对象。
  6. 锁定分支会话。
  7. 将分支会话添加到全局会话中,如果出现异常,解锁分支并抛出异常。
  8. 打印日志并返回分支id。

下面来看看底层是如何实现的:

branchSessionLock(globalSession, branchSession);

io.seata.server.transaction.at.ATCore#branchSessionLock

在这里插入图片描述

根据打印的日志记录来看,应用数据 applicationData 是 null,因此直接进入到子方法。

io.seata.server.session.BranchSession#lock

在这里插入图片描述

io.seata.server.lock.AbstractLockManager#acquireLock

在这里插入图片描述

这个方法会从分支会话中获取所有行锁信息。

// get locks of branch
List<RowLock> locks = collectRowLocks(branchSession);

io.seata.server.lock.AbstractLockManager#collectRowLocks

在这里插入图片描述

上图以其中一个事务分支为例对方法进行了简单的逻辑梳理。该方法根据分支注册请求信息构建了锁对象集合并返回。

顺便说一下,transactionId 实际上就是 xid 中 IP 端口后面的那一长串数字:

  • xid:192.168.2.117:8091:2252230319988862988
  • transactionId:2252230319988862988
  • branchId:2252230319988862990

在这里插入图片描述

回到上一层继续往下深入获取锁。

io.seata.server.storage.db.lock.DataBaseLocker#acquireLock

在这里插入图片描述

io.seata.server.storage.db.lock.LockStoreDataBaseDAO#acquireLock
在这里插入图片描述

这是获取全局锁的主要方法,方法逻辑如下:

  1. 首先,该方法获取数据库连接 conn,并设置自动提交属性为 false。同时,创建 PreparedStatement 对象 ps 和 ResultSet 对象 rs,以及一个用于存储已存在行键的 HashSet 集合 dbExistedRowKeys。

  2. 如果传入的锁对象列表 lockDOs 的大小大于1,则通过过滤去除重复的行键,将其赋值给 lockDOs。这样可以确保锁对象列表中不会存在重复的行键。

  3. 如果 skipCheckLock 参数为 false,说明需要进行锁的检查。即先查询数据库中的锁表,判断是否有其他事务正在持有或正在回滚相同的全局锁。

    • 创建一个查询检查锁的 SQL 语句 checkLockSQL,并将锁对象数量作为参数传递给该语句。
    • 通过 PreparedStatement 对象 ps 执行 checkLockSQL,并将锁对象的行键作为参数设置到 PreparedStatement 对象中。
    • 执行查询并遍历 ResultSet 对象 rs。对于每一行记录,检查是否存在其他事务持有相同的全局锁。
      • 如果存在其他事务持有相同的全局锁,则设置 canLock 标志为 false,并终止循环。
      • 同时,将查询到的数据库中已存在的行键添加到 dbExistedRowKeys 集合中。
    • 如果 canLock 标志为 false,表示无法获取锁,执行回滚操作,并根据 autoCommit 参数和锁的状态判断是否需要抛出异常。
    • 如果 dbExistedRowKeys 集合不为空,表示锁在数据库中已存在,因此需要将这些行键从 lockDOs 列表中移除。
  4. 如果经过锁的检查后,lockDOs 列表为空,表示锁已全部存在于数据库中,无需再次获取锁,直接提交事务并返回 true。

  5. 接下来,执行锁的获取操作。如果 lockDOs 列表中只有一个锁对象,调用 doAcquireLock 方法进行单个锁的获取。如果获取失败,执行回滚操作,并返回 false。

  6. 如果 lockDOs 列表中存在多个锁对象,调用 doAcquireLocks 方法进行批量锁的获取。如果获取失败,执行回滚操作,并返回 false。

  7. 最后,提交事务,关闭 ResultSet、PreparedStatement 对象,根据原始的自动提交属性设置连接的 autoCommit 属性,并关闭数据库连接。

io.seata.server.storage.db.lock.LockStoreDataBaseDAO#doAcquireLock
在这里插入图片描述

获取到全局锁后,会把锁信息保存到数据库表 lock_table 中,在释放锁后记录也会删除。

(完)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Seata】03 - Seata AT 模式全局锁相关知识简单整理 的相关文章

  • 如何将本机库链接到 IntelliJ 中的 jar?

    我正在尝试在 IntelliJ 中设置 OpenCV 但是我一直在弄清楚如何告诉 IntelliJ 在哪里可以找到本机库位置 在 Eclipse 中 添加 jar 后 您可以在 Build Config 屏幕中设置 Native 库的位置
  • 为什么 JTables 使 TableModel 在呈现时不可序列化?

    所以最近我正在开发一个工具 供我们配置某些应用程序 它不需要是什么真正令人敬畏的东西 只是一个具有一些 SQL 脚本生成功能并创建几个 XML 文件的基本工具 在此期间 我使用自己的 AbstractTableModel 实现创建了一系列
  • 如何在 Spring 中禁用使用 @Component 注释创建 bean?

    我的项目中有一些用于重构逻辑的通用接口 它看起来大约是这样的 public interface RefactorAwareEntryPoint default boolean doRefactor if EventLogService wa
  • 谷歌应用程序引擎会话

    什么是java应用程序引擎 默认会话超时 如果我们将会话超时设置为非常非常长的时间 会不会产生不良影响 因为谷歌应用程序引擎会话默认情况下仅存储在数据存储中 就像facebook一样 每次访问该页面时 会话仍然永远存在 默认会话超时设置为
  • 在接口中使用默认方法是否违反接口隔离原则?

    我正在学习 SOLID 原则 ISP 指出 客户端不应被迫依赖于他们所使用的接口 不使用 在接口中使用默认方法是否违反了这个原则 我见过类似的问题 但我在这里发布了一个示例 以便更清楚地了解我的示例是否违反了 ISP 假设我有这个例子 pu
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • Java 公历日历更改时区

    我正在尝试设置 HOUR OF DAY 字段并更改 GregorianCalendar 日期对象的时区 GregorianCalendar date new GregorianCalendar TimeZone getTimeZone GM
  • 检测并缩短字符串中的所有网址

    假设我有一条字符串消息 您应该将 file zip 上传到http google com extremelylonglink zip http google com extremelylonglink zip not https stack
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • Eclipse Maven Spring 项目 - 错误

    I need help with an error which make me crazy I started to study Java EE and I am going through tutorial on youtube Ever
  • Hibernate 的 PersistentSet 不使用 hashCode/equals 的自定义实现

    所以我有一本实体书 public class Book private String id private String name private String description private Image coverImage pr
  • volatile、final 和synchronized 安全发布的区别

    给定一个带有变量 x 的 A 类 变量 x 在类构造函数中设置 A x 77 我们想将 x 发布到其他线程 考虑以下 3 种变量 x 线程安全 发布的情况 1 x is final 2 x is volatile 3 x 设定为同步块 sy
  • Java 和 Python 可以在同一个应用程序中共存吗?

    我需要一个 Java 实例直接从 Python 实例数据存储中获取数据 我不知道这是否可能 数据存储是否透明 唯一 或者每个实例 如果它们确实可以共存 都有其单独的数据存储 总结一下 Java 应用程序如何从 Python 应用程序的数据存
  • 尝试将 Web 服务部署到 TomEE 时出现“找不到...的 appInfo”

    我有一个非常简单的项目 用于培训目的 它是一个 RESTful Web 服务 我使用 js css 和 html 创建了一个客户端 我正在尝试将该服务部署到 TomEE 这是我尝试部署时遇到的错误 我在这里做错了什么 刚刚遇到这个问题 我曾
  • 使用 AsyncTask 传递值

    我一直在努力解决这个问题 但我已经到了不知道该怎么办的地步 我想做的是使用一个类下载文件并将其解析为字符串 然后将该字符串发送到另一个类来解析 JSON 内容 所有部件都可以单独工作 并且我已经单独测试了所有部件 我只是不知道如何将值发送到
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • 找不到符号 NOTIFICATION_SERVICE?

    package com test app import android app Notification import android app NotificationManager import android app PendingIn
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • 双枢轴快速排序和快速排序有什么区别?

    我以前从未见过双枢轴快速排序 是快速排序的升级版吗 双枢轴快速排序和快速排序有什么区别 我在 Java 文档中找到了这个 排序算法是双枢轴快速排序 作者 弗拉基米尔 雅罗斯拉夫斯基 乔恩 本特利和约书亚 布洛赫 这个算法 在许多数据集上提供
  • Spring Rest 和 Jsonp

    我正在尝试让我的 Spring Rest 控制器返回jsonp但我没有快乐 如果我想返回 json 但我有返回的要求 完全相同的代码可以正常工作jsonp我添加了一个转换器 我在网上找到了用于执行 jsonp 转换的源代码 我正在使用 Sp

随机推荐

  • std::move()的学习总结

    目录 1 移动语义 2 std move的实现及使用 3 总结 1 移动语义 移动语义可以使得编译器使用不那么昂贵的移动操作 来替换昂过的复制操作 同拷贝构造函数 拷贝赋值运算符赋予人们复制意义的能力一样 移动构造函数 移动赋值运算符也赋予
  • 火焰识别系统(python实现基于颜色多帧差分)

    实现如下 通过OpenCV基于火焰颜色特征 通过二帧三针差分减少误差 实现火焰定位识别 然后通过ffmpeg实现推流 流媒体服务器为基于nginx的rtmp流插件实现 请百度nginx rtmp 具体实现如下 ffmpeg推流命令 def
  • Django爬过的坑坑~(2020年5月)

    Django爬过的坑坑 2020年5月 大噶好 我作为一名新人 在学习的过程中难免会遇到让人抓狂的坑坑 一丁点小错误就把人搞得头皮发麻 咳咳 首先这次我第一次发博客 目的是想分享一下自己在Django中遇到的各种坑 此坑我用了半个月的时间
  • 问chatgpt关于Android效率最高的列表控件的回答

    在Android中 效率最高的列表控件是RecyclerView RecyclerView是Android官方推荐的列表控件 相比于ListView和GridView 它具有以下优势 复用ViewHolder RecyclerView通过V
  • DP算法题收集汇总

    三种基本背包问题 一 0 1背包问题 问题描述 有n件物品和容量为m的背包 给出i件物品的重量以及价值求解让装入背包的物品重量不超过背包容量 且价值最大 特点
  • Windows下使用Kconfig管理编译配置

    Windows下使用Kconfig管理编译配置 文章目录 Windows下使用Kconfig管理编译配置 存在的问题 解决办法 存在的问题 项目开发过程中 为方便进行编译配置管理 引入了Kconfig python的konfiglib和me
  • sql server服务无法启动怎么办?如何正常启动?

    sql server软件是一款关系型数据库管理系统 具有使用方便可伸缩性好与相关软件集成程度高等优点 并且有些应用软件使用过程中是需要sql server数据库的后台支持的 我们在数据编程操作时经常会使用这款编程软件 在编程时系统有时会提示
  • Qt_信号与槽

    1 信号与槽基本理解 信号 Signal 就是在特定情况下被发射的事件 槽 Slot 就是对信号响应的函数 槽就是一个函数 connect 是 QObject 类的一个静态函数 而 QObject 是所有 Qt 类的基类 在实际调用时可以忽
  • Flink:调用JPMML机器学习模型

    有个需求就是要使用数据分析团队实现好的模型 而且是python的 要求在Flink平台上跑起来提供实时调用模型处理数据 文章目录 背景 JPMML介绍 环境准备 安装 使用 步骤 示例 决策树分类Iris数据集 训练模型并获得PMML文件
  • 什么是强缓存和协商缓存?

    强缓存 使用强缓存策略时 如果缓存资源有效 则直接使用缓存资源 不必再向服务器发起请求 强缓存策略可以通过 http 头信息中的 Expires 属性和 Cache Control 属性两种方式设置 命中后返回 200 服务器通过在响应头中
  • PyCharm里from...import...出现波浪线标红

    PyCharm在遇到模块找不到时 会使用红色波浪线提醒开发者 这本来是一个非常好的功能 但却由于另外一个问题 会给一些Python初学者造成困扰 这一篇文章 我们讲讲工作区导致的这个问题 首先我们创建一个login py文件 它的内容如下
  • webpack打包全流程

    一 webpack 五个核心概念 1 1 Entry 入口 Entry 指示 webpack 以哪个文件为入口起点开始打包 分析构建内部依赖图 1 2 Output 输出 Output 指示 webpack 打包后的资源 bundles 输
  • Playwright + Pytest 自动化测试实战应用

    工具介绍 Playwright是微软公司开发的一款非常强大的开源自动化测试工具 之所以强大有以下原因 支持所有主流浏览器 Chrome Firefox Safari MS Edge 支持无头模式和有头模式运行 提供同步 异步的API 可以结
  • 简述WINDOWS系统重装步骤

    目录 一 备份 二 准备安装媒体 三 BIOS设置 四 安装windows系统 总结 在使用WINDOWS系统的电脑产品时 有时候我们会遇到系统使用过久导致系统卡顿 整理电脑磁盘时误删了系统文件并彻底清除导致电脑无法正常启动或者电脑磁盘因下
  • Linux文件压缩和解压命令【gzip、gunzip、zip、unzip、tar】【详细总结】

    解压和压缩 gzip gunzip gzip 压缩文件 gunzip 解压缩文件 zip unzip zip 命令语法 命令选项 实例 unzip 语法 命令选项 实例 tar 语法 实例 例一 将文件打包成tar包 例二 查阅 tar包内
  • socket.gaierror: [Errno -2] Name or service not known

    执行socket gethostbyname socket gethostname 报 socket gaierror Errno 2 Name or service not known 错误 分析记录如下 更正前 执行命令vi etc h
  • redis主从复制+sentinel集群

    Redis主从介绍 主从服务就是用户在主服务器写入数据后 从服务器在写一份数据 一般用在如下场景 1 辅助实现备份 2 高可用 主从复制只是redis高可用的前提 3 异地容灾 4 分摊负载 redis主从特点介绍 1 redis使用异步复
  • windows下在anaconda中安装tensorflow和keras

    windows下在anaconda中安装tensorflow和keras 一 在anaconda中创建一个新的python环境并安装tensorflow 1 创建环境名为tensorflow python38的python环境 python
  • 微信小程序wx.getUserProfile接口获取用户信息的使用

    前言 调整原因 很多开发者在打开小程序时就通过组件方式唤起getUserInfo弹窗 如果用户点击拒绝 无法使用小程序 这种做法打断了用户正常使用小程序的流程 同时也不利于小程序获取新用户 调整策略 推荐使用 wx getUserProfi
  • 【Seata】03 - Seata AT 模式全局锁相关知识简单整理

    文章目录 前言 参考目录 版本说明 分析整理 1 全局锁的引入说明 2 全局锁相关源码整理 2 1 流程简图 2 2 事务分支注册前的 SQL 相关操作 2 3 注册分支 获取全局锁 前言 上一篇文章介绍了 AT 模式的调用流程 但是有个比