Java中的分布式事务Seata详解

 更新时间:2023年08月30日 09:20:42   作者:余生海  
这篇文章主要介绍了Java中的分布式事务Seata详解,Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案,需要的朋友可以参考下

Seata 是什么?

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。

Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

AT 模式

前提

  • 基于支持本地 ACID 事务的关系型数据库。
  • Java 应用,通过 JDBC 访问数据库。

整体机制

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。

  • 二阶段:

    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。

写隔离

  • 一阶段本地事务提交前,需要确保先拿到全局锁。
  • 拿不到全局锁,不能提交本地事务。
  • 拿全局锁的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

以一个示例来说明:

两个全局事务 tx1 和 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000。

tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的全局锁,本地提交释放本地锁。 tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的全局锁,tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待全局锁。

在这里插入图片描述

tx1 二阶段全局提交,释放全局锁。tx2 拿到全局锁提交本地事务。

xxx

如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果 tx2 仍在等待该数据的全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2 的全局锁等锁超时,放弃全局锁并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。

因为整个过程全局锁在 tx1 结束前一直是被 tx1 持有的,所以不会发生脏写的问题。

读隔离

在数据库本地事务隔离级别读已提交(Read Committed)或以上的基础上,Seata(AT 模式)的默认全局隔离级别是读未提交(Read Uncommitted)。

如果应用在特定场景下,必需要求全局的读已提交,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

在这里插入图片描述

SELECT FOR UPDATE 语句的执行会申请全局锁,如果全局锁被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到全局锁拿到,即读取的相关数据是已提交的,才返回。

出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。

工作机制

以一个示例来说明整个 AT 分支的工作过程。

业务表: product

FieldTypeKey
idbigint(20)PRI
namevarchar(100)
sincevarchar(100)

AT 分支事务的业务逻辑:

update product set name = 'GTS' where name = 'TXC';

一阶段

过程:

  • 解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = ‘TXC’)等相关的信息。
  • 查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。
select id, name, since from product where name = 'TXC';

得到前镜像:

idnamesince
1TXC2014
  • 执行业务 SQL:更新这条记录的 name 为 ‘GTS’。
  • 查询后镜像:根据前镜像的结果,通过主键定位数据。
select id, name, since from product where id = 1`;

得到后镜像:

idnamesince
1GTS2014
  • 插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中。
{
	"branchId": 641789253,
	"undoItems": [{
		"afterImage": {
			"rows": [{
				"fields": [{
					"name": "id",
					"type": 4,
					"value": 1
				}, {
					"name": "name",
					"type": 12,
					"value": "GTS"
				}, {
					"name": "since",
					"type": 12,
					"value": "2014"
				}]
			}],
			"tableName": "product"
		},
		"beforeImage": {
			"rows": [{
				"fields": [{
					"name": "id",
					"type": 4,
					"value": 1
				}, {
					"name": "name",
					"type": 12,
					"value": "TXC"
				}, {
					"name": "since",
					"type": 12,
					"value": "2014"
				}]
			}],
			"tableName": "product"
		},
		"sqlType": "UPDATE"
	}],
	"xid": "xid:xxx"
}
  • 提交前,向 TC 注册分支:申请product表中,主键值等于 1 的记录的全局锁
  • 本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
  • 将本地事务提交的结果上报给 TC。

二阶段-回滚

  1. 收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
  2. 通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
  3. 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理,详细的说明在另外的文档中介绍。
  4. 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
update product set name = 'TXC' where id = 1;
  • 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

二阶段-提交

  1. 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
  2. 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。

附录

回滚日志表

UNDO_LOG Table:不同数据库在类型上会略有差别。

以 MySQL 为例:

FieldType
branch_idbigint PK
xidvarchar(100)
contextvarchar(128)
rollback_infolongblob
log_statustinyint
log_createddatetime
log_modifieddatetime

 代码:

-- 注意此处0.7.0+ 增加字段 context
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

TCC 模式

回顾总览中的描述:一个分布式的全局事务,整体是两阶段提交的模型。

全局事务是由若干分支事务组成的,分支事务要满足两阶段提交的模型要求,即需要每个分支事务都具备自己的:

  • 一阶段 prepare 行为
  • 二阶段 commit 或 rollback 行为

在这里插入图片描述

根据两阶段行为模式的不同,我们将分支事务划分为Automatic (Branch) Transaction ModeManual (Branch) Transaction Mode.

AT 模式基于支持本地 ACID 事务关系型数据库

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动生成补偿操作,完成数据回滚。

相应的,TCC 模式,不依赖于底层数据资源的事务支持:

  • 一阶段 prepare 行为:调用自定义的 prepare 逻辑。
  • 二阶段 commit 行为:调用自定义的 commit 逻辑。
  • 二阶段 rollback 行为:调用自定义的 rollback 逻辑。

所谓 TCC 模式,是指支持把自定义的分支事务纳入到全局事务的管理中。

Saga 模式

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

在这里插入图片描述

理论基础:Hector & Kenneth 发表论⽂ Sagas (1987)

适用场景:

  • 业务流程长、业务流程多
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

优势:

  • 一阶段提交本地事务,无锁,高性能
  • 事件驱动架构,参与者可异步执行,高吞吐
  • 补偿服务易于实现

缺点:

  • 不保证隔离性

 到此这篇关于Java中的分布式事务Seata详解的文章就介绍到这了,更多相关Java分布式事务Seata内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java经典用法总结

    Java经典用法总结

    这篇文章主要介绍了Java经典用法总结,在本文中,尽量收集一些java最常用的习惯用法,特别是很难猜到的用法,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • Java操作压缩包解压过程详解

    Java操作压缩包解压过程详解

    这篇文章主要介绍了Java操作压缩包解压过程,项目开发中,总会遇到解压缩文件的时候,比如用户下载多个文件时,服务端可以将多个文件压缩成一个文件,用户上传资料时,允许上传压缩文件,服务端进行解压读取每一个文件,使用场景是很多的,下面来详细讲解,需要的朋友可以参考下
    2024-10-10
  • 深入理解Java中的构造函数引用和方法引用

    深入理解Java中的构造函数引用和方法引用

    java构造函数,也叫构造方法,是java中一种特殊的函数。函数名与相同,无返回值。方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。下面我们来详细了解一下它们吧
    2019-06-06
  • Java 中HashCode作用_动力节点Java学院整理

    Java 中HashCode作用_动力节点Java学院整理

    这篇文章主要介绍了Java 中HashCode作用以及hashcode对于一个对象的重要性,对java中hashcode的作用相关知识感兴趣的朋友一起学习吧
    2017-05-05
  • Java中接口和抽象类的区别详解

    Java中接口和抽象类的区别详解

    这篇文章主要介绍了Java中接口和抽象类的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Servlet3.0实现文件上传的方法

    Servlet3.0实现文件上传的方法

    本篇文章主要介绍了Servlet实现文件上传的方法,所谓文件上传就是将本地的文件发送到服务器中保存。有兴趣的可以了解一下。
    2017-03-03
  • java爬虫模拟登陆的实例详解

    java爬虫模拟登陆的实例详解

    在本篇文章里小编给大家分享的是一篇关于java爬虫模拟登陆的实例详解内容,有兴趣的朋友们可以参考学习下。
    2021-01-01
  • Java实现数据库图片上传功能详解

    Java实现数据库图片上传功能详解

    这篇文章主要为大家详细介绍了如何使用Java实现数据库图片上传功能,包含从数据库拿图片传递前端渲染,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-03-03
  • swagger的请求参数不显示,@Apimodel的坑点及解决

    swagger的请求参数不显示,@Apimodel的坑点及解决

    这篇文章主要介绍了swagger的请求参数不显示,@Apimodel的坑点及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Spring执行流程和Bean的生命周期详解

    Spring执行流程和Bean的生命周期详解

    这篇文章主要介绍了Spring执行流程和Bean的生命周期详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06

最新评论