《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Seata/build-debugging-environment/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

0. 介绍

2019 年 1 月,阿里巴巴中间件团队发起了开源项目 Fescar(Fast & EaSy Commit And Rollback),和社区一起共建开源分布式事务解决方案。Fescar 的愿景是让分布式事务的使用像本地事务的使用一样,简单和高效,并逐步解决开发者们遇到的分布式事务方面的所有难题。

Fescar 开源后,蚂蚁金服加入 Fescar 社区参与共建,并在 Fescar 0.4.0 版本中贡献了 TCC 模式。

为了打造更中立、更开放、生态更加丰富的分布式事务开源社区,经过社区核心成员的投票,大家决定对 Fescar 进行品牌升级,并更名为 Seata,意为:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事务解决方案。

Seata 融合了阿里巴巴和蚂蚁金服在分布式事务技术上的积累,并沉淀了新零售、云计算和新金融等场景下丰富的实践经验,但要实现适用于所有的分布式事务场景的愿景,仍有很长的路要走。因此,我们决定建立一个完全中立的分布式事务组织,希望更多的企业、开发者能够加入我们,一起打造 Seata。

Seata solution

road map

1. 依赖工具

  • Maven
  • Git
  • JDK
  • IntelliJ IDEA

    注意,IntelliJ IDEA 最好使用最新版本。目前艿艿使用的是 2019.1.2 ,避免出现奇怪的问题。= =~反正我是出了,所以做了升级。

  • MySQL

  • Nacos

2. 源码拉取

本小节,我们需要拉取两个项目的源码:

2.1 获取 Demo 源码

使用 IntelliJ IDEA 从 https://github.com/seata/seata-samples 拉取代码。拉取完成后,Maven 会下载依赖包,可能会花费一些时间,耐心等待下。

2.2 获取 Seata 源码

从官方仓库 https://github.com/seata/seata Fork 出属于自己的仓库。为什么要 Fork ?既然开始阅读、调试源码,我们可能会写一些注释,有了自己的仓库,可以进行自由的提交。😈

本文基于 develop 分支,对应 Seata 的 0.6.0-SNAPSHOT 版本。

艿艿:现在开始,需要一些简单的骚操作,注意落。

  • 1、打开命令行,使用 git clone https://github.com/seata/seata 命令,克隆 Seata 源码到本地。

    如果胖友 Fork 了 Seata 项目,注意替换成自己的仓库地址。

  • 2、打开 IntelliJ IDEA ,点击菜单 [File] -> [Module from Existing Sources] ,选择 Demo 项目。然后,使用 Maven 格式进行导入。最终效果如下图:效果图

    这么做是,方便后面 IDEA 调试 Seata 源码时,使用我们克隆的项目的源码。

  • 3、修改 Demo 项目引用 Seata 的版本号,为克隆的 Seata 项目的版本号(例如本文为 0.6.0-SNAPSHOT)。如下图所示:效果图

艿艿:下面,开始正式的表演。hohoho 。

3. 启动 Seata Server 服务

比较简单,搜到 io.seata.server.Server 类,直接迅猛右键 main 方法,运行,启动完毕。可看到如下日志:

INFO [main]io.seata.core.rpc.netty.AbstractRpcRemotingServer.start:152 -Server started ...

艿艿:距离成功,已经完成了一半。

4. 启动 Demo 项目

Seata 提供了各种 Demo ,艿艿选择了 spring-boot-dubbo-seata 项目,基于 Spring Boot + Dubbo 的示例。

4.1 初始化数据库

艿艿:目前 Seata 暂时只支持 MySQL ,所以胖友一定要注意噢。

  • 1、创建数据库,名字为 db_gts_fescar
  • 2、将 spring-boot-dubbo-seata/sql/db_seata.sql 导入到数据库中,进行表的初始化。

艿艿:可能胖友会有疑惑,使用单库怎么测试分布式事务呢?即使单库,如果多个服务进行事务操作,一样会形成分布式事务。

4.2 启动 Nacos 服务

因为 spring-boot-dubbo-seata 示例,使用 Nacos 作为注册中心,所以需要胖友自己启动一个 Nacos 服务。

艿艿:保持耐心。Nacos 未来我们也是要学习的,现在就是提前演戏了一波。

详细可以参考教程:《官网文档 —— Nacos 支持三种部署模式》

  • 1、打开 https://github.com/alibaba/nacos/releases 网页,下载 Nacos 。艿艿目前看到的最新版本是 1.0.0 ,所以当然下载它。
  • 2、创建数据库,名字为 nacos_devtest 。然后,将 Nacos 所在目录/conf/nacos-mysql.sql 导入数据库中。
  • 3、编辑 Nacos 所在目录/conf/application.properties 配置文件,增加 Nacos 数据库连接。例如如下:

    spring.datasource.platform=mysql

    db.num=1
    db.url.0=jdbc:mysql://180.167.213.26:13306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
    db.user=root
    db.password=你的密码
  • 4、执行 nohup sh bin/startup.sh -m standalone & 命令,启动 Nacos 服务。

  • 5、浏览器打开 http://127.0.0.1:8848/nacos 网页,输入 nacos / nacos 进行登录。

艿艿:至此,我们终于启动 Nacos 服务。此时,来听一首《爱的魔力转圈圈》,放松下心情。

后面,基本就没复杂步骤啦,淡定淡定。

4.3 启动各种项目

4.3.1 启动 samples-storage 项目

搜到 io.seata.samples.integration.storage.StorageGtsFescarExampleApplication 类,直接迅猛右键 main 方法,运行,启动完毕。可看到如下日志:

INFO 29748 --- [imeoutChecker_1] i.s.core.rpc.netty.NettyPoolableFactory  : NettyPool create channel to transactionRole:TMROLE,address:127.0.0.1:8091,msg:< RegisterTMRequest{applicationId='storage-gts-fescar-example', transactionServiceGroup='my_test_tx_group'} >
INFO 29748 --- [imeoutChecker_1] io.seata.core.rpc.netty.RmRpcClient : will connect to 127.0.0.1:8091
INFO 29748 --- [imeoutChecker_1] io.seata.core.rpc.netty.RmRpcClient : RM will register :jdbc:mysql://180.167.213.26:13306/db_gts_fescar?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
INFO 29748 --- [imeoutChecker_1] i.s.core.rpc.netty.NettyPoolableFactory : NettyPool create channel to transactionRole:RMROLE,address:127.0.0.1:8091,msg:< RegisterRMRequest{resourceIds='jdbc:mysql://180.167.213.26:13306/db_gts_fescar?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true', applicationId='storage-gts-fescar-example', transactionServiceGroup='my_test_tx_group'} >
INFO 29748 --- [imeoutChecker_1] io.seata.core.rpc.netty.RmRpcClient : register RM success. server version:0.6.0,channel:[id: 0x56592a3a, L:/127.0.0.1:62656 - R:/127.0.0.1:8091]
INFO 29748 --- [imeoutChecker_1] i.s.core.rpc.netty.NettyPoolableFactory : register success, cost 32 ms, version:0.6.0,role:TMROLE,channel:[id: 0xca65c481, L:/127.0.0.1:62657 - R:/127.0.0.1:8091]
INFO 29748 --- [imeoutChecker_1] i.s.core.rpc.netty.NettyPoolableFactory : register success, cost 41 ms, version:0.6.0,role:RMROLE,channel:[id: 0x56592a3a, L:/127.0.0.1:62656 - R:/127.0.0.1:8091]
  • 已经成功注册到 Seata Server 服务 中。

4.3.2 启动 samples-account 项目

搜到 io.seata.samples.integration.account.AccountGtsFescarExampleApplication 类,直接迅猛右键 main 方法,运行,启动完毕。

效果同 samples-storage 项目。

4.3.3 启动 samples-order 项目

搜到 io.seata.samples.integration.order.OrderGtsFescarExampleApplication 类,直接迅猛右键 main 方法,运行,启动完毕。

效果同 samples-storage 项目。

4.3.4 启动 samples-dubbo-business-call 项目

搜到 io.seata.samples.integration.call.DubboGtsFescarExampleApplication 类,直接迅猛右键 main 方法,运行,启动完毕。

至此,我们已经把需要启动的项目,都启动完毕。此时,我们打开 Nacos 可以看到各个服务的状况。如下图:服务列表

4.4 测试分布式事务

下面,我们将测试两种情况:

  1. 分布式事务正常提交
  2. 分布式事务异常回滚

因为,下面是要模拟调用 HTTP 接口,所以需要胖友有 Postman

4.4.1 正常流程

在 Postman 中,模拟请求如下图:正常 Postman

  • 请求地址:127.0.0.1:8104//business/dubbo/buy
  • 请求数据:

    {
    "userId": "1",
    "commodityCode": "C201901140001",
    "name": "水杯",
    "count": 1,
    "amount": 0.01
    }

请求成功后,我们看看数据的变化。如下图:

  • t_order 表,新增了一条记录。如下图:`t_order`
  • t_storage 表,库存减一。如下图:`t_storage`
  • t_account 表,余额减一。如下图:`t_account`

4.4.2 异常流程

在 Postman 中,模拟请求如下图:异常 Postman

  • 我们故意将商品编号 "commodityCode" 写错成了 "C201901140001xxxx" ,用于模拟分布式事务,因为库存不足,进行回滚。
  • 为了更好的看过过程中的变化,我们在 BusinessServiceImpl 类的 #handleBusiness(BusinessDTO businessDTO) 方法,第 XX 行,打了一个断点。如下图所示:BusinessServiceImpl 断点

做好了这些准备,我们点击 Postman ,执行请求。因为我们在 BusinessServiceImpl 打了断点,所以我们看看执行到此处,数据的变化。如下图:

  • t_order 表,新增了一条记录。如下图:`t_order`
  • t_storage 表,库存不变,因为我们使用了一个不存在的商品。如下图:`t_storage`
  • t_account 表,余额减一。如下图:`t_account`

此时,我们放开断点,执行下去,因为扣库存失败,所以会抛出 DefaultException 异常,从而回滚全局事务。然后呢,数据又恢复:

  • t_order 表,如下图:`t_order`
  • t_storage 表,如下图:`t_storage`
  • t_account 表,如下图:`t_account`

666. 彩蛋

呼呼,搞定~

因为过程可能比较复杂,所以胖友如果中间碰到什么问题,请到【芋道源码】给我留言。

目前网上 Seata 的实战案例比较少,截止 2019-05 的时候,可能有且仅有一个,那就是 https://github.com/YunaiV/onemall 。欢迎 star ,艿艿和基友们,会慢慢进行更新。

开始正式调试源码前,艿艿建议胖友能看看文章:

😊

文章目录
  1. 1. 0. 介绍
  2. 2. 1. 依赖工具
  3. 3. 2. 源码拉取
    1. 3.1. 2.1 获取 Demo 源码
    2. 3.2. 2.2 获取 Seata 源码
  4. 4. 3. 启动 Seata Server 服务
  5. 5. 4. 启动 Demo 项目
    1. 5.1. 4.1 初始化数据库
    2. 5.2. 4.2 启动 Nacos 服务
    3. 5.3. 4.3 启动各种项目
      1. 5.3.1. 4.3.1 启动 samples-storage 项目
      2. 5.3.2. 4.3.2 启动 samples-account 项目
      3. 5.3.3. 4.3.3 启动 samples-order 项目
      4. 5.3.4. 4.3.4 启动 samples-dubbo-business-call 项目
    4. 5.4. 4.4 测试分布式事务
      1. 5.4.1. 4.4.1 正常流程
      2. 5.4.2. 4.4.2 异常流程
  6. 6. 666. 彩蛋