spring cloud Nacos 整合 Seata

导读:本篇文章讲解 spring cloud Nacos 整合 Seata,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com


工程使用的技术及版本


spring cloud Hoxton.SR8


spring cloud alibaba 2.2.1.RELEASE


spring boot 2.3.4.RELEASE


open feign


mysql 8


nacos 1.4.0


seata 1.3.0


mybatis plus 3.2.0

一、Seata 简介

查看源码 https://github.com/Xiao-Y/seata-demo
查看源码 查看源码 查看源码 查看源码

1. Seata 如何处理呢

在这里插入图片描述

Business 是业务入口,在程序中会通过注解来说明他是一个全局事务,这时他的角色为 TM(事务管理者)。

Business 会请求 TC(事务协调器,一个独立运行的服务),说明自己要开启一个全局事务,TC 会生成一个全局事务ID(XID),并返回给 Business。

Business 得到 XID 后,开始调用微服务,例如调用 Storage。

Storage 会收到 XID,知道自己的事务属于这个全局事务。Storage 执行自己的业务逻辑,操作本地数据库。

Storage 会把自己的事务注册到 TC,作为这个 XID 下面的一个分支事务,并且把自己的事务执行结果也告诉 TC。

此时 Storage 的角色是 RM(资源管理者),资源是指本地数据库。

Order、Account 的执行逻辑与 Storage 一致。

在各个微服务都执行完成后,TC 可以知道 XID 下各个分支事务的执行结果,TM(Business) 也就知道了。

Business 如果发现各个微服务的本地事务都执行成功了,就请求 TC 对这个 XID 提交,否则回滚。

TC 收到请求后,向 XID 下的所有分支事务发起相应请求。

各个微服务收到 TC 的请求后,执行相应指令,并把执行结果上报 TC

2. 核心组件

  • 事务协调器 TC:维护全局和分支事务的状态,指示全局提交或者回滚。

  • 事务管理者 TM:开启、提交或者回滚一个全局事务。

  • 资源管理者 RM:管理执行分支事务的那些资源,向TC注册分支事务、上报分支事务状态、控制分支事务的提交或者回滚。

3. 具体工作过程

在这里插入图片描述

  • TM 请求 TC,开始一个新的全局事务,TC 会为这个全局事务生成一个 XID。
  • XID 通过微服务的调用链传递到其他微服务。
  • RM 把本地事务作为这个XID的分支事务注册到TC。
  • TM 请求 TC 对这个 XID 进行提交或回滚。
  • TC 指挥这个 XID 下面的所有分支事务进行提交、回滚。

二、Seata 详细工作流程示例

在这里插入图片描述

三、启动 seata 服务端

seata 在读取配置文件时有多种方式,这里采用 nacos 的方式,生产上优先使用这种方式。

1. 下载seatea 服务端

我的源码工程中已经存在,在 temp 文件夹中

在这里插入图片描述

2.修改 config.txt 文件,根据需要保存。修改数据库相关

config.txt 文件在源码中需要下载 Source code(zip) (我的源码工程中已经存在,在 temp 文件夹中)解压后 seata-1.4.1\script\config-center

执行 seata-1.4.1\script\config-center\nacos\nacos-config.sh 将配置文件导入到 nacos 中

nacos-config.sh -h <ip> -p <port> -g SEATA_GROUP -t <namespace> -u <username> -w <password>

例如:

不带命名空间的

nacos-config.sh -h 127.0.0.1 -p 8761 -g SEATA_GROUP -u nacos -w nacos

带命名空间的,新建命名空间 seata-dev

nacos-config.sh -h 127.0.0.1 -p 8761 -g SEATA_GROUP -u nacos -w nacos -t seata-dev

service.vgroupMapping.my_test_tx_group=seata-server-cluster
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true%26characterEncoding=utf8%26useSSL=false%26autoReconnect=true%26serverTimezone=Asia/Shanghai
store.db.user=root
store.db.password=root

spring cloud Nacos 整合 Seata

3.修改 registry.conf 文件,修改 nacos 的地址、用户名和密码。

配置信息从 nacos 中获取(就是上面导入的)

# 注册中心配置
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10
  nacos {
    application = "seata-server"
    serverAddr = "119.23.27.78:8761"
    group = "SEATA_GROUP"
    namespace = "seata-dev"
    cluster = "seata-server-cluster"
    username = "nacos"
    password = "nacos"
  }
}

# 配置中心配置
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"
  nacos {
    serverAddr = "119.23.27.78:8761"
    namespace = "seata-dev"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

4、新建数据库 seata

-- seata 库
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table`  (
  `branch_id` bigint(0) NOT NULL,
  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `transaction_id` bigint(0) NULL DEFAULT NULL,
  `resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `status` tinyint(0) NULL DEFAULT NULL,
  `client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gmt_create` datetime(6) NULL DEFAULT NULL,
  `gmt_modified` datetime(6) NULL DEFAULT NULL,
  PRIMARY KEY (`branch_id`) USING BTREE,
  INDEX `idx_xid`(`xid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table`  (
  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `transaction_id` bigint(0) NULL DEFAULT NULL,
  `status` tinyint(0) NOT NULL,
  `application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `timeout` int(0) NULL DEFAULT NULL,
  `begin_time` bigint(0) NULL DEFAULT NULL,
  `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gmt_create` datetime(0) NULL DEFAULT NULL,
  `gmt_modified` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`xid`) USING BTREE,
  INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,
  INDEX `idx_transaction_id`(`transaction_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table`  (
  `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_id` bigint(0) NULL DEFAULT NULL,
  `branch_id` bigint(0) NOT NULL,
  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gmt_create` datetime(0) NULL DEFAULT NULL,
  `gmt_modified` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`row_key`) USING BTREE,
  INDEX `idx_branch_id`(`branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

5. 启动 seata-server.bat

在这里插入图片描述

seata-server.bat -p 8091

seata-server.bat -p 8092

四、调用端

1. 新建测试库 account、order、storage

-- storage 添加测试表
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- order 添加测试表
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT 0,
  `money` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- account 添加测试表
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `money` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- 创建 UNDO_LOG 表,每个库中都要执行
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2. 新建工程

在这里插入图片描述

Account、Order、Storage中的pom.xml中添加

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- 对应 seata 的版本 -->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>

application.yml 中添加

seata:
  # 开启自动装配
  enabled: true
  # 本客户端的微服务名称
  application-id: ${spring.application.name}
  # 读取哪个事务分组
  tx-service-group: my_test_tx_group
  # 配置中心设置
  config:
    type: nacos
    nacos:
      # 与上面的命名空间相同
      namespace: seata-dev
      username: nacos
      password: nacos
      # nacos 的ip和端口
      server-addr: ${nacos-server-addr}
      # 读取的配置分组
      group: SEATA_GROUP
  # 注册中心设置
  registry:
    type: nacos
    nacos:
      # SEATA服务中心的微服务名,此处与服务端保持一致
      application: seata-server
      # 与上面的命名空间相同
      namespace: seata-dev
      # nacos 的ip和端口
      server-addr: ${nacos-server-addr}
      username: nacos
      password: nacos

Business-BusinessApi.java 中调用

import com.xiaoy.business.feign.OrderFeign;
import com.xiaoy.business.feign.StorageFeign;
import com.xiaoy.business.service.BusinessService;
import com.xiaoy.business.vo.OrderVo;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author liuyongtao
 * @since 2021-3-2 17:02
 */
@Service
public class BusinessServiceImpl implements BusinessService {

    @Autowired
    private OrderFeign orderFeign;
    @Autowired
    private StorageFeign storageFeign;

    @Override
    @GlobalTransactional
    public boolean business(OrderVo orderVo) {
        orderFeign.insertOrder(orderVo);
        storageFeign.subStorage(orderVo.getCommodityCode(), orderVo.getCount());
        return true;
    }
}

Order-OrderApi.java

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoy.order.dao.OrderDao;
import com.xiaoy.order.dto.Order;
import com.xiaoy.order.feign.AccountFeign;
import com.xiaoy.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author liuyongtao
 * @since 2021-3-2 15:57
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderDao, Order> implements OrderService {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private AccountFeign accountFeign;

    @Override
    @Transactional
    public boolean insertOrder(Order order) {
        orderDao.insert(order);
        accountFeign.subAccount(order.getUserId(), order.getMoney());
        return true;
    }
}

3. 测试

在这里插入图片描述
在这里插入图片描述

查看源码 https://github.com/Xiao-Y/seata-demo
查看源码 查看源码 查看源码 查看源码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/15396.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!