Seata 分布式事务使用
分布式事务
在分布式系统中,如果一个业务需要多个服务合作完成,而且每一个服务都有事务,多个事务必须同时成功或失败,这样的事务就是分布式事务。其中的每个服务的事务就是一个分支事务。整个业务称为全局事务。
安装 seata
docker 安装 seata
配置参考 https://blog.csdn.net/weixin_42633509/article/details/145204282
添加数据库
1 | -- 1. 执行语句创建名为 seata 的数据库 |
拉取 docker 镜像
1 | docker pull seataio/seata-server:2.0.0 |
启动临时容器
1 | docker run -d -p 8091:8091 -p 7091:7091 --name seata-server seataio/seata-server:2.0.0 |
拷贝临时容器的配置至宿主机
1 | docker cp seata-server:/seata-server/resources/. F:/docker/data/seata/config/ |
配置 application.yml 文件信息使用
1 | # Copyright 1999-2019 Seata.io Group. |
启动docker容器, 启动前对容器内部互联docker 网络 查看配置
1 | docker run --name seata-server \ |
至此 seata 启动起来
使用Seata
seata
Seata事务管理中有三个重要的角色:
- TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
- TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) - 资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态
实现XA模式
XA模式的优点是什么?
- 事务的强一致性,满足ACID原则。
- 常用数据库都支持,实现简单,并且没有代码侵入
XA模式的缺点是什么? - 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
- 依赖关系型数据库实现事务
Seata的starter已经完成了XA模式的自动装配,实现非常简单,步骤如下:
修改application.yml文件(每个参与事务的微服务),开启XA模式:
1 | seata: |
在需要使用分布式事务的方法上面使用 @GlobalTransactional
1 | @GlobalTransactional |
实现AT模式
简述AT模式与XA模式最大的区别是什么?
- XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
- XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
- XA模式强一致;AT模式最终一致
添加 数据表到每个 微服务中去修改 对应 application.yaml 或者nacos 统一配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
sql1
2seata:
data-source-proxy-mode: AT # 开启数据源代理的AT模式
Seata 表介绍
在 Seata 中,分布式事务被分成全局事务和分支事务。全局事务是由业务发起方启动的事务,而分支事务则是指全局事务在一个服务内的局部事务。为了协调这些事务,Seata 使用了 AT(Automatic Transaction)、TCC(Try-Confirm-Cancel)、Saga 和 XA 模式等几种不同的事务模式。
branch_table :
branch_table 是 Seata 框架中的一个重要组成部分,用于分布式事务管理。Seata 是一种开源的分布式事务解决方案,旨在提供高性能和易用性的同时保证数据的一致性。
- 分支ID(branch_id):唯一标识一个分支事务。
- 全局事务ID(xid):关联到全局事务。
- 分支类型(branch_type):指示该分支事务的类型,比如AT、TCC等。
- 资源描述(resource_desc):描述了资源的位置或相关信息,例如数据库连接信息。
- 状态(status):表示分支事务的状态,如正在进行、已提交、已回滚等。
- 这些信息对于协调分布式事务的提交和回滚至关重要。当一个全局事务需要提交或回滚时,Seata 服务器会根据 branch_table 中的信息来决定如何操作每个分支事务,从而确保整个分布式事务的一致性。
global_table :
global_table 主要记录了全局事务相关的元数据,这些信息对于协调和管理分布式事务的生命周期至关重要。
- Transaction ID (xid): 全局事务的唯一标识符。每个分布式事务都有一个唯一的 xid,它被用来关联该事务下的所有分支事务。
- Transaction Name: 事务的名称或描述,有时可以用来标识事务的目的或类型。
- Status: 全局事务的状态,例如初始化、正在进行、提交、回滚等状态。这个字段帮助跟踪事务的进度和结果。
- Application ID: 发起事务的应用程序ID,有助于识别哪个应用启动了该事务。
- Transaction Service Group: 服务组名,与配置相关,有助于定位具体的事务协调器。
- Timeout: 事务的超时时间设置,如果事务在这个时间内没有完成(提交或回滚),则会被认为是超时。
- Begin Time: 事务开始的时间戳,记录了事务创建的具体时间。
- Application Data: 可选字段,有时会用来保存一些业务相关的额外信息或者上下文。
lock_table:
lock_table 在 Seata 分布式事务框架中扮演着关键角色,主要用于解决分布式事务中的数据锁定问题。在分布式事务处理过程中,为了保证数据的一致性和隔离性,Seata 需要对涉及的资源进行锁定,以防止并发事务造成的数据不一致问题。
- RowKey: 这是一个唯一标识符,用来标识被锁定的记录。它通常由表名和主键值组成,确保在整个数据库范围内是唯一的。
- XID: 全局事务ID,用于关联到具体的全局事务。这帮助 Seata 确定哪个全局事务持有了特定的锁。
- Transaction ID (transaction_id): 与 XID 相关,有时用于内部引用或当需要直接关联到一个事务管理器时使用。
- Branch ID (branch_id): 分支事务ID,表示持有该锁的分支事务。这对于分布式事务中的细粒度控制非常重要。
- Lock Name: 锁的名称或描述,虽然不是所有实现都必需,但它可能用于提供更详细的锁信息或便于管理和调试。
lock_table 的主要功能是记录哪些数据项被哪些事务所锁定,以便其他事务尝试访问这些数据项时可以识别出存在冲突,并采取相应的措施(例如等待当前事务释放锁或者抛出异常)。通过这种方式,Seata 能够有效地避免脏读、不可重复读等并发问题,同时保证了数据的一致性和完整性。
异常问题
- 以下 可能是 jdk17 的问题 通过添加 解决如下问题
1
--add-opens=java.base/java.lang=ALL-UNNAMED
1
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'globalTransactionScanner' defined in class path resource [io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.seata.spring.annotation.GlobalTransactionScanner]: Factory method 'globalTransactionScanner' threw exception; nested exception is java.lang.ExceptionInInitializerError
- 集成seata报错:can not register RM,err:can not connect to services-server.
通过启动时docker 添加 对应的 -e SEATA_IP=192.168.5.18 -e SEATA_PORT=8091
