Alibaba Seata 实现分布式事务(二) 2022-04-12 程序之旅,记录 1 条评论 1177 次阅读 ## Alibaba Seata 实现分布式事务(二) > 之前有学习了 Seata 中的原理及其解决方案,这里就对 Seata 进行真正的落地实现,配置之前的分布式项目实现全局一致性事务。 gitee 项目地址:https://gitee.com/teaegg/spring-cloud-alibaba-template.git ### Nacos 注册中心与配置中心 [参考文章](https://blog.mufeng.info/index.php/archives/276/) ### 部署 TC 组件 Seata-Server #### 第一步,下载 Seata-Server 服务器上安装 JDK 1.8,访问 github 上 release 下载 Linux 安装包(也可以 docker 安装)。[下载地址](https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.tar.gz) 解压后的目录结构 ``` [root@localhost seata-server-1.4.2]# ll 总用量 24 drwxr-xr-x. 2 root root 53 4月 9 00:09 bin drwxr-xr-x. 4 502 games 156 4月 9 00:09 conf drwxr-xr-x. 3 502 games 8192 4月 9 00:09 lib -rw-r--r--. 1 502 games 11365 5月 13 2019 LICENSE drwxr-xr-x. 2 502 games 6 4月 25 2021 logs [root@localhost seata-server-1.4.2]# ``` > 官方文档可以访问 https://seata.io/zh-cn/docs/user/quickstart.html #### 第二步,配置 registry.conf 在文件目录 conf 下配置 nacos 的注册 registry.conf ```conf registry{ # seata-server 支持以下几种注册中心,默认 file 改为nacos type = "nacos" nacos { application = "seata-server" serverAddr = "127.0.0.1:8848" group = "SEATA_GROUP" namespace = "" # 集群名称 cluster = "default" username = "nacos" password = "nacos" } config { # 配置中心 # file、nacos 、apollo、zk、consul、etcd3 type = "nacos" nacos { serverAddr = "127.0.0.1:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" # dataId = "seataServer.properties" } } ``` #### 第三步,在 Nacos 配置中心中初始化 Seata 配置 官方给出的配置文件 https://github.com/seata/seata/blob/1.4.2/script/config-center/config.txt 在 seata-server 根目录下创建 config.txt 文件,把 github 中的 config.txt 文件内容拷贝到根目录下的 config.txt 中,并修改以下几个配置项。 ``` store.mode=db store.db.user=root store.db.password=root ``` 表示使用数据库存储 Seata-server 的全局事务数据。 保存后访问第二个文件 https://github.com/seata/seata/blob/1.4.2/script/config-center/nacos/nacos-config.sh,下载到根目录的 script 文件夹中。 授权 nacos-config.sh 并执行,`./nacos-config.sh -h 127.0.0.1` 导入 config.txt 配置。 ![image-20220409003727722](https://mufeng-blog.oss-cn-beijing.aliyuncs.com/typecho/image-20220409003727722.png) #### 第四步,创建并初始化 Seata-Server 全局事务数据库 同样在 github 路径下载 sql 文件,https://github.com/seata/seata/blob/1.4.2/script/server/db/mysql.sql。数据库执行。 ```sh $ mysql -uroot -p $ create database seata; $ source /usr/local/seata/seata-server-1.4.2/script/server/db/mysql.sql ``` 执行完成后,数据库创建三张表 - global_table:保存全局事务数据 - branch_table:保存分支事务数据 - lock_table:保存锁定资源数据 #### 第五步,启动 seata-server ```sh $ sh bin/seata-server.sh ``` ![image-20220409004353478](https://mufeng-blog.oss-cn-beijing.aliyuncs.com/typecho/image-20220409004353478.png) ### 开发 RM 资源管理器 在 Seata 中 RM 资源管理器代表处理具体业务的模块,例如:订单服务创建订单、会员服务增加积分和库存服务减少库存,以下就以这三个服务进行 seata 的分布式 ID 的实现。 主要用到的技术 Spring Boot + Mybatis-Plus,分别给三个微服务创建三个数据库,a-service、b-service 和 c-service,其中每个库中都包含 RM 资源管理器的回滚日志表 undo_log,表的结构是官方提供的,[下载地址](https://github.com/seata/seata/blob/1.4.2/script/client/at/db/mysql.sql)。1.4.2 版本的 undo_log.sql ```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'; ``` #### 订单服务 a-service 订单表为 ```sql DROP TABLE IF EXISTS `order`; CREATE TABLE `t_order` ( `order_id` int(255) NOT NULL AUTO_INCREMENT COMMENT '订单编号', `goods_id` int(32) NOT NULL COMMENT '商品编号', `member_id` int(32) NOT NULL COMMENT '会员编号', `quantity` int(255) NOT NULL COMMENT '购买数量', `points` int(255) NOT NULL COMMENT '增加会员积分', PRIMARY KEY (`order_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; ``` 创建 a-service 服务,pom.xml 添加依赖 ```xml org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-starter-openfeign com.alibaba.cloud spring-cloud-starter-alibaba-seata io.seata seata-all io.seata seata-spring-boot-starter io.seata seata-all 1.4.2 io.seata seata-spring-boot-starter 1.4.2 org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine com.baomidou mybatis-plus-boot-starter 3.5.0 mysql mysql-connector-java runtime org.projectlombok lombok io.springfox springfox-swagger2 2.9.2 io.swagger swagger-models io.swagger swagger-models 1.5.21 io.springfox springfox-swagger-ui 2.9.2 ``` > start-alibaba-seata 依赖内置的是旧版 seata 客户端,需要排除自行引入最新 1.4.2,保持客户端与 seata-server 版本一致。 配置 application.yml ```yaml logging: level: root: debug server: port: 7000 spring: application: name: a-service datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/a-service username: root password: root cloud: nacos: discovery: namespace: public password: nacos server-addr: 127.0.0.1:8848 username: nacos seata: enabled: true # 事务服务分组名 tx-service-group: my_test_tx_group # 是否启用数据源代理 enable-auto-data-source-proxy: true # 事务服务配置 service: vgroup-mapping: # 事务分组对应集群名称 my_test_tx_group: default # seata-server 服务的 IP 地址与端口 grouplist: default: 127.0.0.1:8091 enable-degrade: false disable-global-transaction: false # nacos 配置中心信息 config: type: nacos nacos: namespace: server-addr: 127.0.0.1:8848 group: SEATA_GROUP username: nacos password: nacos cluster: default # nacos 注册中心信息 registry: type: nacos nacos: application: seata-server server-addr: 127.0.0.1:8848 group: SEATA_GROUP namespace: username: nacos password: nacos cluster: default mybatis-plus: mapper-locations: classpath*:/mapper/*Mapper.xml global-config: banner: false db-config: update-strategy: ignored insert-strategy: ignored ``` 启动类 ```java @EnableFeignClients // OpenFeign @SpringBootApplication @MapperScan(basePackages = {"info.mufeng.aservice.mapper", "info.mufeng.aservice.entity"}) public class AServiceApplication { public static void main(String[] args) { SpringApplication.run(AServiceApplication.class, args); } } ``` controller ```java @RestController @RequestMapping("/order") public class OrderController { @Resource private IOrderService orderService; @GetMapping("create") public String createOrder(Integer orderId, Integer memberId, Integer goodsId, Integer points, Integer quantity) throws JsonProcessingException { Map result = new HashMap<>(); Order order = new Order(); order.setOrderId(orderId); order.setMemberId(memberId); order.setGoodsId(goodsId); order.setPoints(points); order.setQuantity(quantity); boolean b = orderService.saveOrUpdate(order); result.put("code", "0"); result.put("message", "create order success"); return new ObjectMapper().writeValueAsString(result); } } ``` 调用接口尝试 http://127.0.0.1:7000/order/create,返回结果 ```json { "code": "0", "message": "create order success" } ``` > 其他两个服务 b-service 和 c-service 一样的实现过程,这里就不做多的描述 ### 验证分布式事务 主要的业务逻辑是 a-service -> b-service -> c-service。 请求 a-service 接口,b-service 的 RM 端负责提交与删除本地的 undo_log 日志。 ![image-20220412220820740](https://mufeng-blog.oss-cn-beijing.aliyuncs.com/typecho/image-20220412220820740.png) 如果 c-service 抛出异常,a-service 会全局回滚事务。 ![image-20220412221011046](https://mufeng-blog.oss-cn-beijing.aliyuncs.com/typecho/image-20220412221011046.png) 打赏: 微信, 支付宝 标签: spring cloud alibaba, seata, 分布式事务 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
恭贺大佬喜提新域名