springcloud nacos 2.3.0+seata 2.0.0(Docker部署) SeataAT模式

3,167 阅读5分钟

前置操作

  • 创建network,指定容器内部通信ip网段

    # 172.20.0.0/16表示容器内部通信网段范围:172.20.0.0~172.20.255.55 
    docker network create --subnet=172.20.0.0/16 ht
    

安装nacos容器

  • 创建一个临时容器,单机模式启动

    docker run --name nacos-standalone -e MODE=standalone -p 8848:8848 -d -p 9848:9848  nacos/nacos-server:v2.3.0
    
  • 拷贝容器内配置文件至宿主机

    docker cp nacos-standalone:/home/nacos/conf C:\MY\Docker\nacos
    docker cp nacos-standalone:/home/nacos/data C:\MY\Docker\nacos
    docker cp nacos-standalone:/home/nacos/logs C:\MY\Docker\nacos
    
  • 使用mysql存储nacos数据,导入nacos数据库

    nacos数据库文件存放目录:容器内部 /home/nacos/conf/mysql-schema.sql

  • 修改conf文件夹下的application.properties

    # spring
    server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos}
    server.contextPath=/nacos
    server.port=${NACOS_APPLICATION_PORT:8848}
    server.tomcat.accesslog.max-days=30
    server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
    server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}
    server.error.include-message=ALWAYS
    # default current work dir
    server.tomcat.basedir=file:.
    #*************** Config Module Related Configurations ***************#
    ### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
    #spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:}
    spring.sql.init.platform=mysql
    nacos.cmdb.dumpTaskInterval=3600
    nacos.cmdb.eventTaskInterval=10
    nacos.cmdb.labelTaskInterval=300
    nacos.cmdb.loadDataAtStart=false
    db.num=1
    db.url.0=jdbc:mysql://mysql:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
    db.user.0=root
    db.password.0=123456
    ## DB connection pool settings
    db.pool.config.connectionTimeout=30000
    db.pool.config.validationTimeout=10000
    db.pool.config.maximumPoolSize=20
    db.pool.config.minimumIdle=2
    ### The auth system to use, currently only 'nacos' and 'ldap' is supported:
    #开启鉴权
    nacos.core.auth.enabled=true
    nacos.core.auth.system.type=nacos
    ### worked when nacos.core.auth.system.type=nacos
    ### The token expiration in seconds:
    nacos.core.auth.plugin.nacos.token.expire.seconds=18000
    ### The default token:
    #设置秘钥 随意Base64编码 长度至少32字节
    nacos.core.auth.plugin.nacos.token.secret.key=WWxoc2RWbFhUblpqTWxKc1lsYzVlbVJJVm10bFVUMDk=
    ### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
    nacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}
    nacos.core.auth.enable.userAgentAuthWhite=${NACOS_AUTH_USER_AGENT_AUTH_WHITE_ENABLE:false}
    #随意配置下面两个属性,不配置启动报错
    nacos.core.auth.server.identity.key=test
    nacos.core.auth.server.identity.value=test
    ## spring security config
    ### turn off security
    nacos.security.ignore.urls=${NACOS_SECURITY_IGNORE_URLS:/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**}
    # metrics for elastic search
    management.metrics.export.elastic.enabled=false
    management.metrics.export.influx.enabled=false
    nacos.naming.distro.taskDispatchThreadCount=10
    nacos.naming.distro.taskDispatchPeriod=200
    nacos.naming.distro.batchSyncKeyCount=1000
    nacos.naming.distro.initDataRatio=0.9
    nacos.naming.distro.syncRetryDelay=5000
    nacos.naming.data.warmup=true
    nacos.console.ui.enabled=true
    nacos.core.param.check.enabled=true
    

    重点介绍下需要修改的配置:开启鉴权,使用数据库中账号和密码登录(默认:nacos/nacos)

    ​
    spring.sql.init.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://mysql:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
    db.user.0=root
    db.password.0=123456
    #开启鉴权 登录账号和密码在数据库中users表
    nacos.core.auth.enabled=true
    #设置秘钥 随意Base64编码 长度至少32字节
    nacos.core.auth.plugin.nacos.token.secret.key=WWxoc2RWbFhUblpqTWxKc1lsYzVlbVJJVm10bFVUMDk=
    #随意配置下面两个属性,不配置启动报错
    nacos.core.auth.server.identity.key=test
    nacos.core.auth.server.identity.value=test
    

image.png

  • 删除临时容器,创建正式nacos容器并挂载目录

    使用单机模式,其余配置参考官方文档:Nacos Docker

    docker run -itd \
    --name nacos \
    --network ht \
    --ip 172.20.0.3 \
    -e MODE=standalone \
    -e JVM_XMS=512M -e JVM_XMX=512M -e JVM_XMN=256M \
    -p 8848:8848 -p 9848:9848 -p 9849:9849 \
    -v C:\MY\Docker\nacos\conf:/home/nacos/conf \
    -v C:\MY\Docker\nacos\data:/home/nacos/data \
    -v C:\MY\Docker\nacos\logs:/home/nacos/logs \
     nacos/nacos-server:v2.3.0
    
  • 新建开发环境命名空间(根据自己需求,使用默认public也可以),名字自定义,ID尤为重要

image.png

安装seata容器

  • 创建临时容器

    docker run -itd --name seata-server -p 8091:8091 -p 7091:7091 seataio/seata-server:2.0.0
    
  • 拷贝容器内resources目录下所有配置文件至宿主机,此处没有挂载seata日志文件,seata日志文件容器内部默认存储地址应该是 /root/logs/seata/(没有找到相关资料)

    docker cp seata-server:/seata-server/resources/. C:\MY\Docker\seata\config
    
  • 创建seata数据库,建表语句如下: 官方地址

    -- -------------------------------- The script used when storeMode is 'db' --------------------------------
    -- the table to store GlobalSession data
    CREATE TABLE IF NOT EXISTS `global_table`
    (
        `xid`                       VARCHAR(128) NOT NULL,
        `transaction_id`            BIGINT,
        `status`                    TINYINT      NOT NULL,
        `application_id`            VARCHAR(32),
        `transaction_service_group` VARCHAR(32),
        `transaction_name`          VARCHAR(128),
        `timeout`                   INT,
        `begin_time`                BIGINT,
        `application_data`          VARCHAR(2000),
        `gmt_create`                DATETIME,
        `gmt_modified`              DATETIME,
        PRIMARY KEY (`xid`),
        KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
        KEY `idx_transaction_id` (`transaction_id`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    ​
    -- the table to store BranchSession data
    CREATE TABLE IF NOT EXISTS `branch_table`
    (
        `branch_id`         BIGINT       NOT NULL,
        `xid`               VARCHAR(128) NOT NULL,
        `transaction_id`    BIGINT,
        `resource_group_id` VARCHAR(32),
        `resource_id`       VARCHAR(256),
        `branch_type`       VARCHAR(8),
        `status`            TINYINT,
        `client_id`         VARCHAR(64),
        `application_data`  VARCHAR(2000),
        `gmt_create`        DATETIME(6),
        `gmt_modified`      DATETIME(6),
        PRIMARY KEY (`branch_id`),
        KEY `idx_xid` (`xid`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    ​
    -- the table to store lock data
    CREATE TABLE IF NOT EXISTS `lock_table`
    (
        `row_key`        VARCHAR(128) NOT NULL,
        `xid`            VARCHAR(128),
        `transaction_id` BIGINT,
        `branch_id`      BIGINT       NOT NULL,
        `resource_id`    VARCHAR(256),
        `table_name`     VARCHAR(32),
        `pk`             VARCHAR(36),
        `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
        `gmt_create`     DATETIME,
        `gmt_modified`   DATETIME,
        PRIMARY KEY (`row_key`),
        KEY `idx_status` (`status`),
        KEY `idx_branch_id` (`branch_id`),
        KEY `idx_xid` (`xid`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    ​
    CREATE TABLE IF NOT EXISTS `distributed_lock`
    (
        `lock_key`       CHAR(20) NOT NULL,
        `lock_value`     VARCHAR(20) NOT NULL,
        `expire`         BIGINT,
        primary key (`lock_key`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    ​
    INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
    INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
    INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
    INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
    
  • 修改config目录下application.yml配置文件,使用nacos作为注册/配置中心,mysql存储事务日志,所有配置参考同目录下application.example.yml

    #  Copyright 1999-2019 Seata.io Group.
    #
    #  Licensed under the Apache License, Version 2.0 (the "License");
    #  you may not use this file except in compliance with the License.
    #  You may obtain a copy of the License at
    #
    #  http://www.apache.org/licenses/LICENSE-2.0
    #
    #  Unless required by applicable law or agreed to in writing, software
    #  distributed under the License is distributed on an "AS IS" BASIS,
    #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #  See the License for the specific language governing permissions and
    #  limitations under the License.
    
    server:
      port: 7091
    
    spring:
      application:
        name: seata-server
    
    logging:
      config: classpath:logback-spring.xml
      file:
        path: ${log.home:${user.home}/logs/seata}
      extend:
        logstash-appender:
          destination: 127.0.0.1:4560
        kafka-appender:
          bootstrap-servers: 127.0.0.1:9092
          topic: logback_to_logstash
    
    console:
      user:
        username: seata
        password: seata
    
    seata:
      # 配置中心 nacos
      config:
        # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
        type: nacos
        nacos:
          # 容器内部ip 创建nacos容器时已指定
          server-addr: 172.20.0.3:8848
          namespace: dev
          group: DEV_GROUP
          username: nacos   
          password: nacos
          # 新版nacos默认 /nacos前缀
          context-path: /nacos
          ##if use MSE Nacos with auth, mutex with username/password attribute
          #access-key:
          #secret-key:
          # 配置中心文件名
          data-id: seata-dev.properties
    
      # 注册中心 nacos
      registry:
        # support: nacos 、 eureka 、 redis 、 zk  、 consul 、 etcd3 、 sofa
        type: nacos
        preferred-networks: 30.240.*
        nacos:
          application: seata-server
          #nacos容器内部ip 可通过命名 docker inspect [容器名] 查看ip
          server-addr: 172.20.0.3:8848
          group: DEV_GROUP
          namespace: dev
          cluster: default
          username: nacos 
          password: nacos
          context-path: /nacos
          ##if use MSE Nacos with auth, mutex with username/password attribute
          #access-key:
          #secret-key:
    
      #  server:
      #    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
      security:
        secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
        tokenValidityInMilliseconds: 1800000
        ignore:
          urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**
    
  • nacos注册中心创建配置文件,Data ID、Group和上述配置文件保持一致;配置文件内容可直接复制官方文档config.txt,此处只需配置store,其余配置基本都有默认值

image.png

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption
#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
#使用mysql8驱动
store.db.driverClassName=com.mysql.cj.jdbc.Driver
#设置时区
store.db.url=jdbc:mysql://mysql:3306/seata?serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
  • 创建正式容器,挂载目录

    注:SEATA_IP指定seata-server启动的IP, 该IP用于向注册中心注册时使用;设置一个能容器外部能ping通的地址,在同一台服务器部署设置为本机ip地址; 从 Seata 2.0 开始,JDBC 驱动需放在 lib/jdbc/ 目录下,需自行在宿主机添加对应的jdbc驱动

    docker run -itd --name seata --network ht --ip 172.20.0.4 -e SEATA_IP=192.168.1.5  -p 8091:8091 -p 7091:7091 -v C:\MY\Docker\seata\config:/seata-server/resources C:\MY\Docker\seata\lib\jdbc:/lib/jdbc  seataio/seata-server:2.0.0
    
  • 查看nacos注册列表

image.png

  • 查看注册中心ip

image.png

  • 查看seata启动日志,观察nacos配置文件是否生效

image.png

Order模块

  • 创建数据库,导入undo_log、order_tbl表

    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;
    ​
    ​
    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;
    
  • 创建项目,加入依赖 (注:使用最新版nacos和seata可能会有兼容问题,仅练习用)

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    ​
        <parent>
            <groupId>com.xxx</groupId>
            <artifactId>seata_at</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    ​
        <groupId>com.xxx</groupId>
        <artifactId>order</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    ​
        <packaging>jar</packaging>
    ​
        <dependencies>
    ​
            <!-- nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>com.alibaba.nacos</groupId>
                        <artifactId>nacos-client</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    ​
         
            <!-- 使用2.3.0 nacos -->
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
                <version>2.3.0</version>
            </dependency>
    ​
       
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    ​
            <!-- seata -->
            <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>
    ​
            <!-- 使用2.0.0 seata -->
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-spring-boot-starter</artifactId>
                <version>2.0.0</version>
            </dependency>
    ​
    ​
            <!-- loadbalancer -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            </dependency>
    ​
            <!-- openfeign -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    ​
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
    ​
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
            </dependency>
    ​
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    ​
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
    ​
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    ​
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
        </dependencies>
    ​
    ​
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring.boot.version}</version>
                </plugin>
            </plugins>
        </build></project>
    
  • 配置nacos、seata、feign

    server:
      port: 8081
    spring:
      application:
        name: order
      profiles:
        active: dev
      cloud:
        nacos:
          # 注册中心
          discovery:
            server-addr: 127.0.0.1:8848
            username: nacos
            password: nacos
            namespace: dev
            group: DEV_GROUP
          # 配置中心
          config:
            server-addr: 127.0.0.1:8848
            context-path: /nacos
            username: nacos
            password: nacos
            namespace: dev
            group: DEV_GROUP
            #☆ 配置文件后缀名  cloud项目启动时,自动调用nacos配置中心中DataID = ${spring.application.name}-{spring.profiles.active}.${spring.cloud.nacos.config.file-extension} (business-dev.yml) 文件
            file-extension: yml
            
    # 使用nacos负载均衡
        loadbalancer:
          nacos:
            enabled: true
            
      config:
        #☆ 导入Nacos配置中心的配置文件
        import:
          - optional:nacos:${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}?refresh=true
          
    seata:
      enabled: true
      application-id: order-seata
      #设置分组名称
      tx-service-group: shop_tx_group
      service:
        vgroup-mapping:
          # 当前分组的集群名称,seata单机模式集群名称默认为default
          shop_tx_group: default
      registry:
        type: nacos
        nacos:
          # 配置seata服务在注册中心服务名,默认为seata-server
          application: seata-server
          server-addr: 127.0.0.1:8848
          context-path: /nacos
          username: nacos
          password: nacos
          namespace: dev
          group: DEV_GROUP
          cluster: default
          
    feign:
      client:
        config:
          # default:对所有服务生效     需要对单个服务配置将default改为服务名
          default:
            # 设置连接超时时间
            connect-timeout: 3000
            # 设置读取数据超时时间
            read-timeout: 2000
            # 调用日志打印等级,需要同步将Feign调用类的日志等级设置为Debug才生效
            logger-level: basic      
    
  • nacos配置中心创建order-dev.yml文件,并配置数据库信息

image.png

  • 启动类添加@EnableDiscoveryClient、@EnableFeignClients注解

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class OrderApplication {
    ​
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    ​
    }
    
  • 创建通用模块,编写全局异常处理

    @RestControllerAdvice
    public class GlobalExceptionHandle {
    ​
        //ResponseStatus必须写,否则远程调用默认成功
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        @ExceptionHandler(ServiceException.class)
        public R serviceException(ServiceException serviceException){
            return R.fail(serviceException.getMessage());
        }
    }
    ​
    
  • 使用OpenFeign远程调用

    // nacos注册名
    @FeignClient("account") 
    public interface AccountClient {
    ​
        /**
         * 注:@RequestParam注解不能少,否则会报错
         */
        @GetMapping("/account/debit")
        R debit(@RequestParam("userId") String userId, @RequestParam("money") Integer money);
    ​
    }
    
  • 编写生成订单接口

    @RestController
    public class OrderController {
    ​
        @Resource
        private IOrderService orderService;
    ​
    ​
        /**
         * 创建订单
         */
        @GetMapping("/create")
        public R create(String userId, String commodityCode, Integer orderCount){
            orderService.create(userId,commodityCode,orderCount);
            return R.success();
        }
    ​
    }
    
    @Service
    public class OrderServiceImpl implements IOrderService {
    ​
        @Resource
        private AccountClient accountClient;
    ​
        @Resource
        private OrderMapper orderMapper;
    ​
        //添加@GlobalTransactional注解,实现全局事务,默认为AT模式
        @GlobalTransactional 
        @Override
        public void create(String userId, String commodityCode, Integer orderCount) {
            try {
            //先创建订单再扣减余额,方便测试
                //计算总费用
                int orderMoney = calculate(commodityCode, orderCount);
                //生成订单
                Order order = new Order();
                order.setUserId(userId);
                order.setCommodityCode(commodityCode);
                order.setCount(orderCount);
                order.setMoney(orderMoney);
                int isCreate = orderMapper.insert(order);
                if(isCreate<=0){
                    throw new ServiceException("订单创建失败");
                }
                //扣减余额
                accountClient.debit(userId,orderMoney);
            } catch (Exception e) {
                throw new ServiceException(e.getMessage());
            }
        }
    ​
        private int calculate(String commodityCode, int orderCount) {
            //假设每件商品500
            return 500*orderCount;
        }
    ​
    }
    
  • 测试接口,发生异常,事务回滚

image.png

Account模块

  • 数据库

    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;
    ​
    ​
    DROP TABLE IF EXISTS `order_tbl`;
    CREATE TABLE `order_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;
    
  • 配置和Order模块一致

  • 编写扣减余额接口

        /**
         * 扣减余额
         */
        @GetMapping("/debit")
        public R debit(String userId, Integer money){
            accountService.debit(userId,money);
            return R.success();
        }
    

Gitee地址:seata_at: seata AT模式 (gitee.com)