使用Seata处理分布式事务

事务(Transaction)

  事务是一种机制、一个操作序列,包含了一组数据库操作命令。事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行,因此事务是一个不可分割的工作逻辑单元。

分布式事务

  分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。


常见的分布式事务解决方案有2PC、3PC、TCC、本地消息表、消息事务、最大努力通知等。下面记录一下使用Seata解决分布式事务。


Seata 是什么

  Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

主要名词:

TC (Transaction Coordinator) - 事务协调者

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

TM (Transaction Manager) - 事务管理器

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

RM (Resource Manager) - 资源管理器

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

Seata使用

以当前1.5.2版本为例:

服务端安装

  1. 下载服务端文件,下载地址
  2. 上传到服务器并解压,我这里放到/opt/seata目录下
  3. 准备使用Nacos作为配置和注册中心,执行配置:
cd /opt/seata/script/config-center/nacos #切换到目录
./nacos-config-interactive.sh #执行

根据提示输入Nacos地址和用户名密码,等待完成

  1. 启动:
cd /opt/seata/bin 
./seata-server.sh

启动后访问服务器ip:7091即可访问Seata管理页面,用户名密码默认均为Seata。如下图

image-20220719230859157

同时可以在Nacos的管理界面看到已经注册了Seata服务:

image-20220719231003895

至此,服务端安装配置完成。


项目中使用

模拟场景,项目中存在account服务和order服务操作数据库,另有web服务同时调用account和order。

项目结构如下:

image-20220719231832720

  1. 数据准备
    演示用,就不分库了,不同服务使用同一个数据库,在实际使用中,微服务每个服务应该对应各自的数据库。
    使用Seata的AT模式,每个数据库中都要建立undo_log表记录回滚记录,SQL如下:
-- 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 = utf8 COMMENT ='AT transaction mode undo table';
  1. 项目准备
    项目是就是一个简单的SpringCloud分布式项目,详细的就不贴代码了,最后会有代码地址。只贴一下Seata的核心引用和配置:
    pom文件增加Seata的引用
<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion> <!--剔除掉老版本的Seata -->
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.5.2</version>
        </dependency>

yml配置

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: default_tx_group #这里要和nacos里配置的一致
  enable-auto-data-source-proxy: true
  config:
    type: nacos
    nacos:
      namespace:
      serverAddr: 10.168.1.201:8848
      group: SEATA_GROUP
      userName: "nacos"
      password: "nacos"
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 10.168.1.201:8848
      namespace:
      userName: "nacos"
      password: "nacos"
  1. 测试
    测试代码如下:使用 @GlobalTransactional开启全局事务
@Override
    public void noSeata() {
        userAccountClient.save(userId,BigDecimal.ZERO);
        System.out.println(1/0);
        ordersClient.save(userId,UUID.randomUUID().toString());
    }

    @Override
    @GlobalTransactional
    public void hasSeata() {
        userAccountClient.save(userId,BigDecimal.ZERO);
        System.out.println(1/0);
        ordersClient.save(userId,UUID.randomUUID().toString());
    }

结果是调用noSeata方法,会抛异常,但account会保存数据
调用hasSeata方法,异常后account数据会回滚,这一点从日志中也能体现:

2022-07-19 23:33:26.787  INFO 10204 --- [nio-8089-exec-1] c.b.s.a.s.impl.UserAccountServiceImpl    : save user account:{"balance":0,"userId":1}
Hibernate: insert into user_account (balance, create_time, update_time, user_id, version) values (?, ?, ?, ?, ?)
2022-07-19 23:33:26.990  INFO 10204 --- [nio-8089-exec-1] c.b.s.a.s.impl.UserAccountServiceImpl    : saved user account:{"balance":0,"createTime":1658244806823,"id":21,"updateTime":1658244806823,"userId":1,"version":0}
2022-07-19 23:33:27.155  INFO 10204 --- [h_RMROLE_1_1_16] i.s.c.r.p.c.RmBranchRollbackProcessor    : rm handle branch rollback process:xid=10.168.1.201:8091:639797021460082695,branchId=639797021460082696,branchType=AT,resourceId=jdbc:mysql://10.168.1.201:3306/seata-demo,applicationData={"autoCommit":false,"skipCheckLock":true}
2022-07-19 23:33:27.158  INFO 10204 --- [h_RMROLE_1_1_16] io.seata.rm.AbstractRMHandler            : Branch Rollbacking: 10.168.1.201:8091:639797021460082695 639797021460082696 jdbc:mysql://10.168.1.201:3306/seata-demo
2022-07-19 23:33:27.211  INFO 10204 --- [h_RMROLE_1_1_16] i.s.r.d.undo.AbstractUndoLogManager      : xid 10.168.1.201:8091:639797021460082695 branch 639797021460082696, undo_log deleted with GlobalFinished
2022-07-19 23:33:27.213  INFO 10204 --- [h_RMROLE_1_1_16] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_Rollbacked

可以看到最后做了回滚。

注意:undo_log表在回滚之后会删除记录,如果要观察记录,最好在项目中打断点。


以上,Seata使用AT模式实现分布式事务完成,测试项目代码地址

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白效正

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值