使用 Seata 支持分布式事务

使用 Seata 解决 Dubbo 服务数据一致性问题,支持分布式事务。

本示例演示如何使用 Apache Seata 实现 Dubbo 分布式事务功能,保证数据一致性。

Apache Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 在Dubbo中集成Seata实现分布式事务非常方便,只需简单几步即可完成,本文将通过一个示例带你快速体验,示例总体架构图如下:

seata-flow

开始前,请先完成以下内容:

  1. 下载示例源码

    1. git clone --depth=1 https://github.com/apache/dubbo-samples.git

    进入示例源码目录:

    1. cd dubbo-samples/2-advanced/dubbo-samples-seata
  2. 下载最新版的seata-server二进制包至本地。

步骤 1:建立数据库并初始化相关测试数据

  • 本文将使用MySQL 5.7 (更多支持的数据库可在文末查看附录)。 进入dubbo-samples-seata的script目录,找到dubbo_biz.sql和undo_log.sql两个数据库脚本文件,内容如下:

undo_log.sql是Seata AT 模式需要 UNDO_LOG

  1. -- for AT mode you must to init this sql for you business database. the seata server not need it.
  2. CREATE TABLE IF NOT EXISTS `undo_log`
  3. (
  4. `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
  5. `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
  6. `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
  7. `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
  8. `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
  9. `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
  10. `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
  11. UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
  12. ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
  13. ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);

dubbo_biz.sql是示例业务表以及初始化数据

  1. DROP TABLE IF EXISTS `stock_tbl`;
  2. CREATE TABLE `stock_tbl`
  3. (
  4. `id` int(11) NOT NULL AUTO_INCREMENT,
  5. `commodity_code` varchar(255) DEFAULT NULL,
  6. `count` int(11) DEFAULT 0,
  7. PRIMARY KEY (`id`),
  8. UNIQUE KEY (`commodity_code`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  10. DROP TABLE IF EXISTS `order_tbl`;
  11. CREATE TABLE `order_tbl`
  12. (
  13. `id` int(11) NOT NULL AUTO_INCREMENT,
  14. `user_id` varchar(255) DEFAULT NULL,
  15. `commodity_code` varchar(255) DEFAULT NULL,
  16. `count` int(11) DEFAULT 0,
  17. `money` int(11) DEFAULT 0,
  18. PRIMARY KEY (`id`)
  19. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  20. DROP TABLE IF EXISTS `account_tbl`;
  21. CREATE TABLE `account_tbl`
  22. (
  23. `id` int(11) NOT NULL AUTO_INCREMENT,
  24. `user_id` varchar(255) DEFAULT NULL,
  25. `money` int(11) DEFAULT 0,
  26. PRIMARY KEY (`id`)
  27. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  28. ---INITIALIZE THE ACCOUNT TABLE
  29. INSERT INTO account_tbl(`user_id`,`money`) VALUES('ACC_001','1000');
  30. ---INITIALIZE THE STOCK TABLE
  31. INSERT INTO stock_tbl(`commodity_code`,`count`) VALUES('STOCK_001','100');

请依次执行以下操作:

  • 1.1 创建seata数据库(实际业务场景中会使用不同的数据库,本文为了方便演示仅创建一个数据库,所有的表都在该数据库中创建)
  • 1.2 执行undo_log.sql表中的脚本完成AT模式所需的undo_log表创建
  • 1.3 执行dubbo_biz.sql表中的脚本完成示例业务表创建以及测试数据的初始化

步骤 2:更新spring-boot应用配置中的数据库连接信息

请将以下3个子模块的数据库连接信息更新为你的信息,其他配置无需更改,至此,客户端的配置已经完毕。

  • dubbo-samples-seata-account
  • dubbo-samples-seata-order
  • dubbo-samples-seata-stock
  1. url: jdbc:mysql://127.0.0.1:3306/seata?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useOldAliasMetadataBehavior=true
  2. username: root
  3. password: 123456

步骤 3:启动Seata-Server

  • 本文使用的是Seata-Server V2.0.0版本。

请将下载的Seata-Server二进制包解压,并进入bin目录,然后执行以下命令即可启动Seata-Server。

如果你是Mac OS 或者Linux操作系统,请执行:

  1. ./seata-server.sh

或者你是Windows操作系统,请执行:

  1. ./seata-server.bat

步骤 4:启动示例

一切准备就绪,开始启动示例

请依次启动以下子项目:

  • 4.1 Account Service
  • 4.2 Order Service
  • 4.3 Stock Service
  • 4.4 Business Service

步骤 5:查看分布式事务执行结果

通过访问以下链接,可以测试分布式事务成功提交流程:

http://127.0.0.1:9999/test/commit?userId=ACC\_001&commodityCode=STOCK\_001&orderCount=1

分布式事务成功提交时,业务表的数据将正常更新,请注意观察数据库表中的数据。

通过访问以下链接,可以测试分布式事务失败回滚流程:

http://127.0.0.1:9999/test/rollback?userId=ACC\_001&commodityCode=STOCK\_001&orderCount=1

分布式事务失败回滚时,业务表的数据将没有任何改变,请注意观察数据库表中的数据。

附录

  • 支持的事务模式:Seata目前支持AT、TCC、SAGA、XA等模式,详情请访问Seata官网进行了解
  • 支持的配置中心:Seata支持丰富的配置中心,如zookeeper、nacos、consul、apollo、etcd、file(本文使用此配置中心,无需第三方依赖,方便快速演示),详情请访问Seata配置中心进行了解
  • 支持的注册中心:Seata支持丰富的注册中心,如eureka、sofa、redis、zookeeper、nacos、consul、etcd、file(本文使用此注册中心,无需第三方依赖,方便快速演示),详情请访问Seata注册中心进行了解
  • 支持的部署方式:直接部署、Docker、K8S、Helm等部署方式,详情请访问Seata部署方式进行了解
  • 支持的API:Seata的API分为两大类:High-Level API 和 Low-Level API,详情请访问Seata API进行了解
  • 支持的数据库:Seata支持MySQL、Oracle、PostgreSQL、TiDB、MariaDB等数据库,不同的事务模式会有差别,详情请访问Seata支持的数据库进行了解
  • 支持ORM框架:Seata 虽然是保证数据一致性的组件,但对于 ORM 框架并没有特殊的要求,像主流的Mybatis,Mybatis-Plus,Spring Data JPA, Hibernate等都支持。这是因为ORM框架位于JDBC结构的上层,而 Seata 的 AT,XA 事务模式是对 JDBC 标准接口操作的拦截和增强。详情请访问Seata支持的ORM框架进行了解
  • 支持的微服务框架:Seata目前支持Dubbo、gRPC、hsf、http、motan、sofa等框架,同时seata提供了丰富的拓展机制,理论上可以支持任何微服务框架。详情请访问Seata支持的微服务框架进行了解
  • SQL限制:Seata 事务目前支持 INSERT、UPDATE、DELETE 三类 DML 语法的部分功能,这些类型都是已经经过Seata开源社区的验证。SQL 的支持范围还在不断扩大,建议在本文限制的范围内使用。详情请访问Seata SQL限制进行了解

最后修改 September 13, 2024: Refactor website structure (#2860) (1a4b998f54b)