首页 > 编程语言 >Java: Seata实战部署使用

Java: Seata实战部署使用

时间:2022-11-16 17:13:53浏览次数:32  
标签:实战 事务 Java Seata 回滚 提交 SQL seata

目录

背景

由于业务发展,在Place Order时接入了Promotion模块,要进行核销Coupon的动作,由于动作在不同的服务上,同时也要保证事务一致性,@Transactional注解已经不能满足需求,所以考虑引入Seata

基础概念

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

tx-service-group - 事务分组

事务分组是seata的资源逻辑概念。即可以按微服务的需要对事务进行逻辑上分组,每组取一个名字

在客户端(微服务)配置。
在Spring的配置参数形式如下: seata.tx-service-group=mytest-tx-group 或者用spring.cloud.alibaba.seata.tx-service-group配置
如以上不指定,则逻辑事务分组名默认规则为:spring.application.name值+"-seata-service-group"

vgroup-mapping - 服务端节点seata-server组成的集群cluster名

需要在客户端(微服务)中,对每个逻辑事务分组指定映射使用的vgroup-mapping(即服务端的cluster)。
通过此映射关系调整,即可切换到不同服务端cluster(异地多机房容灾,cluster="shanghai",cluster="suzhou"...)。

在客户端(微服务)配置。
指定逻辑事务分组映射到vgroup-mapping(vgroup-mapping的值需要与seata-server中registry.conf中的cluster保持一致)。 在Spring的配置参数形式如下: seata.service.vgroup-mapping.default-tx-group=default
其中:default-tx-group为事务分组名 等号的右侧 default 与seata-server的cluster名相同
image
image
image

@GlobalTransactional

注解选项:
timeoutMills:超时时间
name:事务的名字
rollbackFor:指定函数抛出哪些异类class会进行全局回滚(不指定默认为RuntimeException)。
noRollbackFor:指定函数抛出哪些异类class不会进行全局回滚。

Client环境

	<spring.boot.version>2.6.4</spring.boot.version>
	<spring.cloud.version>2021.0.1</spring.cloud.version>
	<spring.cloud.alibaba.version>2021.1</spring.cloud.alibaba.version>
	<nacos.version>2.0.3</nacos.version>
	<seata.version>1.4.2</seata.version>
	<dubbo.version>3.0.12</dubbo.version>

AT模式

引用Seata文档描述

  • 在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
    image
  • 两阶段提交
    二阶段如果是提交的话,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。
    image
  • 两阶段回滚
    二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。
    image
    AT 模式的一阶段、二阶段提交和回滚均由 Seata 框架自动生成,用户只需编写“业务 SQL”,便能轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案。

业务场景:扣减库存

  1. 一阶段

    1. 解析SQL:可认为 RM 封装了 DataSource,这里会得到SQL类型(UPDATE),表(goods),条件(where gid=100)等信息
    2. 生成前镜像:比如SQL是 update * where,那记录时把 UPDATE 改成 SELECT 就得到了前镜像的结果集(相当于备份数据)
    3. 执行业务SQL
    4. 生成后镜像:同样,再 SELECT 一下记录起来,此时count=9(也是在备份数据,因为分支事务SQL执行完是会本地提交的)
    5. 记录undolog:undolog 在 mysql 里面是用来做回滚的,这里实际就是将前后镜像组合,然后用 json 存到 UNDO_LOG 表中
    6. 提交前,向TC注册分支:这里会申请 goods 表中主键值等于 100 的记录的全局锁
    7. 提交本地事务:业务数据的更新和前面生成的 undolog 一并提交
    8. 将本地事务提交的结果上报给 TC
      image
  2. 二阶段(提交)

    1. TM 向 TC 发起全局提交
    2. TC 向 RM 发起分支提交(传递XID)
    3. RM 将请求放入一个异步任务的队列中,并马上返回提交成功的结果给 TC
    4. 异步任务阶段的分支提交请求将异步和批量地删除相应 undolog
      image
  3. 二阶段(回滚)

    1. 收到 TC 的分支回滚请求,开启一个本地事务
    2. 通过 XID 和 Branch ID 找到相应的 undolog
    3. 校验脏写:后镜像与当前数据库数据比较,如有不同则说明已被当前全局事务外的动作做了修改,此时需根据配置策略来处理
    4. 还原数据:根据前后镜像,生成逆向SQL并“回滚”(相当于重新写入一次)
    5. 删除undolog
    6. 提交本地事务,并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC
      注意:分支事务的回滚由TC控制,所以RM一定要把异常抛出,如果自己处理了,则无法回滚
      image

问题踩坑

日期序列化问题 (Seata 1.4.2)

问题描述:当Seata版本为1.4.x时,如果业务表中有datetime类型,就会出现如下错误

	com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
	Type id handling not implemented for type java.lang.Object (by serializer of type com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer) 
	(through reference chain: io.seata.rm.datasource.undo.BranchUndoLog["sqlUndoLogs"]
	->java.util.ArrayList[0]
	->io.seata.rm.datasource.undo.SQLUndoLog["beforeImage"]
	->io.seata.rm.datasource.sql.struct.TableRecords["rows"]->java.util.ArrayList[0]
	->io.seata.rm.datasource.sql.struct.Row["fields"]->java.util.ArrayList[2]
	->io.seata.rm.datasource.sql.struct.Field["value"])

解决方案:
1. 将Seata升级至1.5.x版本,即可解决该问题,但要注意项目中使用的dubbo版本,否则很有可能出现下述Dubbo版问题
2. 修改undo_log默认序列化方式,修改为kryo
image

       <dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>kryo</artifactId>
            <version>4.0.2</version>
        </dependency>
        <dependency>
            <groupId>de.javakaffee</groupId>
            <artifactId>kryo-serializers</artifactId>
            <version>0.42</version>
        </dependency>

Dubbo版本问题(Seata 1.5.2 | Dubbo 3.0.x 启动报错)

解决方案:
1. Seata降版本至1.4.2 | Dubbo 3.0.x ☑️
2. Dubbo降版本至2.x | Seata 1.5.2
image

JDK版本问题(Seata 1.4.2 | JDK 17 启动报错)

解决方案:切换成11可以解决
image

标签:实战,事务,Java,Seata,回滚,提交,SQL,seata
From: https://www.cnblogs.com/tanhaoo/p/16892968.html

相关文章

  • JavaScript语法变量以及变量typeof
    JavaScript-语法-变量变量:一小块存储数据的内存空间(一片存储数据的内存区域)Java语言是强类型语言,而JavaScript是弱类型语言强类型:规定类型(在开辟变量存储空间时,定义了......
  • Java8 新特性
    Java8新特性 Java8新特性之Lambda和Stream(一)Lambda#1.what?#Lambda是java8的一个新特性,可以大幅度减少代码量;关注于"做什么",而不是"怎么做",可以通过匿名......
  • Java之拼音工具类的使用
    在自动生成字段key时,字段的key可以设置成使用字段名的拼音。拼音工具类实现如下:packagecom.cmit.kapok.system.utils;importnet.sourceforge.pinyin4j.PinyinHelper......
  • 武警vr训练系统沉浸式实战教学让训练更有效
    近年来VR核心技术不断突破,市场规模也逐渐扩大,应用越来越广泛。很多公安武警也开始采取VR训练的模式,通过VR,既有真实场景般的沉浸感,又避免了可能的安全隐患,保证了训练的效果......
  • (笔者推荐)【Java权威指南】「官方文档-中英互译」AQS的源码注释分析,贯穿总体核心流程
    前提说明本文主要针对于Java官方文档中的先关的官方注释进行中英文互译,保证了源码坐着的设计思路以及相关知识技能介绍分析等,本文主要进行介绍AQS的源码官方注释的含义介绍,......
  • Javascript简单实现深拷贝
    利用递归方式遍历所有属性进行深层对象拷贝:functioncloneDeep(object){if(typeof(object)=='object'){if(Array.isArray(object)){......
  • java切图片圆角
    importxyz.laremehpe.FileUtil.FileChooser;importjavax.imageio.ImageIO;importjava.awt.*;importjava.awt.geom.Ellipse2D;importjava.awt.image.BufferedIma......
  • Java NIO和IO的区别
    1.IO是面向流的,NIO是面向缓冲区的。2.JavaIO的各种流是阻塞的,这就意味着,当一个线程调用read()或write()时,该线程被阻塞,直到有一些数据被读取。JavaNIO的非阻塞模式,使一个......
  • P1422 小玉家的电费(Java)
    题目描述夏天到了,各家各户的用电量都增加了许多,相应的电费也交的更多了。小玉家今天收到了一份电费通知单。小玉看到上面写:据闽价电[2006]27号规定,月用电量在 150150......
  • Java引用类型参数传递
    结论:1)当使用基本数据类型作为方法的形参时,在方法体中对形参的修改不会影响到实参的数值2)当使用引用数据类型作为方法的形参时,若在方法体中修改形参指向的数据内容,则会对实......