ShardingSphere 5.3 は Seata 分散トランザクションを統合 | Spring Cloud 61

I.はじめに

次の一連の章を通して説明します。

docker-compose は Seata Server の高可用性デプロイメントを実装します | Spring Cloud 51

Seata AT モード理論の研究、トランザクション分離と部分的なソースコード分析 | Spring Cloud 52

Spring Boot が Seata を AT モード分散トランザクションと統合する例 | Spring Cloud 53

Seata XA モード理論の学習、使用方法、注意事項 | Spring Cloud54

Seata TCC モード理論の学習、本番レベルの使用例の構築と注意点 | Spring Cloud55

Seata TCC モードでの冪等性、一時停止、空のロールバックの問題を解決する | Spring Cloud56

Seata Saga モード理論の学習、本番レベルの使用例構築と注意点 (1) | Spring Cloud57

Seata Saga モード理論の学習、本番レベルの使用例構築と注意点 (2) | Spring Cloud58

Seataの4つのモード比較まとめ|Spring Cloud 59

私たちは、、 、、 およびトランザクション モードSeata理論的かつ多次元の比較と概要を完了し、ビジネス例を通じてそれらの使用法を深く理解しました。ATXATCCSaga

データベースとテーブルのシャーディングは、データベース拡張で最も一般的に使用される処理方法であり、最もShardingSphere 広く使用されているデータ シャーディング ミドルウェアとして、ShardingSphere分散トランザクションをサポートしSeata、データの一貫性を保証します。この記事では、データ シャーディング シナリオでShardingSphere統合をSeata使用して (リモート) 分散トランザクション呼び出しを行い、統合プロセス中に注意する必要がある事項について詳しく説明します。

不要なスペースを削減するために、この章は、次のように構成されている以前のいくつかの章の内容を適用します。ご自身で参照してください。

ShardingSphereデータシャーディングを実現し、関連コンテンツを実現します。

Spring Boot は ShardingSphere を統合してデータ断片化を実装します (1) | Spring Cloud 40

Spring Boot は ShardingSphere を統合してデータの断片化を実現します (2) | Spring Cloud 41

Spring Boot は ShardingSphere を統合してデータの断片化を実現します (3) | Spring Cloud 42

ShardingSphere 5.3シリーズ構成アップグレードガイド:

ShardingSphere 5.3 シリーズ Spring 構成アップグレードガイド | Spring Cloud 47

SeataATパターン分散トランザクションの例に関連するコンテンツを利用します。

docker-compose は Seata Server の高可用性デプロイメントを実装します | Spring Cloud 51

Seata AT モード理論の研究、トランザクション分離と部分的なソースコード分析 | Spring Cloud 52

Spring Boot が Seata を AT モード分散トランザクションと統合する例 | Spring Cloud 53

2. プロジェクトの全体構成

ここに画像の説明を挿入ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ディレクトリ構造の分析:

  • common-at: エンティティ クラス、openfeign インターフェイス、統合例外処理などを含むパブリック モジュール。

  • account-at: ユーザーのアカウント情報を照会/変更できるアカウント サービス。-resourcemanagerRM (Resource Manager)ロールの場合

    ブランチ トランザクションを管理し、TCフォーク トランザクションと対話してブランチ トランザクションのステータスを登録および報告し、ブランチ トランザクションのコミットまたはロールバックを駆動するリソース。

  • storage-at: 倉庫サービス。商品の在庫数量を照会・変更できます。-resourcemanagerRM (Resource Manager)ロールの場合

上記の内容については、Spring Boot Integration Seata using AT Mode Distributed Transaction Example | Spring Cloud 53 を参照していただき、これを踏まえて変更はありません。

  • order-sharding-database-at:オーダーサービス、ご注文いただけます。TM (Transaction Manager)-トランザクションマネージャーロールの場合

    この章の焦点は、ShardingSphereデータ シャーディング ルールの定義、分散トランザクションの開始のための統合、およびリモート マイクロサービス呼び出しの作成に使用することですSeata

3. 構築時のシャーディングデータベースの注文

3.1 完全な依存関係

seata/openfeign-at/order-sharding-database-at/pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>openfeign-at</artifactId>
        <groupId>com.gm</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-sharding-database-at</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.gm</groupId>
            <artifactId>common-at</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.gm</groupId>
            <artifactId>common-tcc</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

        <!-- 解决shardingsphere集成依赖版本冲突和算法依赖包 -->
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.33</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core</artifactId>
            <version>5.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-transaction-base-seata-at</artifactId>
            <version>5.3.2</version>
            <!-- 排除掉shardingsphere-transaction-base-seata-at默认的seata版本,以免版本不一致出现问题-->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 注意一定要引入对版本,要引入spring-cloud版本seata,而不是springboot版本的seata-->
        <!-- 引入spring-cloud-starter-alibaba-seata解决openfeign远程调用传递xid问题 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <!-- 排除掉springcloud默认的seata版本,以免版本不一致出现问题-->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
            <version>1.6.1</version>
            <!-- Could not deserialize ATN with version 4 (expected 3). -->
            <exclusions>
                <exclusion>
                    <groupId>org.antlr</groupId>
                    <artifactId>antlr4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

各依存パッケージの上のコメントをご自身で確認してください。それぞれの状況が詳細に説明されています。

3.2 完全な設定ファイル

プロジェクト設定ファイルは以下の 4 つに分かれています。

  • ブートストラップ.yml
  • seta.conf
  • レジストリ.conf
  • レジストリ.conf

3.2.1 ブートストラップ.yml

server:
  port: 3012

spring:
  application:
    name: @artifactId@
  cloud:
    nacos:
      username: @nacos.username@
      password: @nacos.password@
      discovery:
        server-addr: ${
    
    NACOS_HOST:nacos1.kc}:${
    
    NACOS_PORT:8848}
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    url: jdbc:shardingsphere:classpath:sharding.yaml

# 此处配置是为了实现利用openfeign传播xid
seata:
  enabled: true


management:
  endpoints:
    web:
      exposure:
        include: '*'

logging:
  level:
    io.seata: info

# mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

予防:

  • seata.enabled=trueopenfeignこの構成は、伝播するグローバルトランザクションの使用を実現するためのものですxid

3.2.2 seta.conf

client {
    
    
    application.id = order-sharding-database-at
    transaction.service.group = mygroup
}

Seata関連する設定については、次のソース コードを参照してくださいorg.apache.shardingsphere.transaction.base.seata.at.SeataATShardingSphereTransactionManager

ここに画像の説明を挿入

トランザクション マネージャーが初期化されるSeataATShardingSphereTransactionManagerと、構成ファイルが読み取られseata.conf、上記の構成情報がロードされます。

3.2.3 レジストリ.conf

Seata登録センターと構成センターの構成:

registry {
    
    
  type = "nacos"

  nacos {
    
    
    application = "seata-server"
    serverAddr = "192.168.0.31:8848"
    group = "DEFAULT_GROUP"
    namespace = "a4c150aa-fd09-4595-9afe-c87084b22105"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}

config {
    
    
  type = "nacos"

  nacos {
    
    
    serverAddr = "192.168.0.31:8848"
    namespace = "a4c150aa-fd09-4595-9afe-c87084b22105"
    group = "DEFAULT_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
}

3.2.4 シャーディング.yaml

shardingsphereデータ シャーディング ルールと分散トランザクション構成を定義します。

dataSources:
  ds1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://192.168.0.35:3306/db1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: '1qaz@WSX'
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1

  ds2:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://192.168.0.46:3306/db2?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: '1qaz@WSX'
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1

rules:

  - !TRANSACTION
    defaultType: BASE
    providerType: Seata

  - !SHARDING
    # 数据分片规则配置
    tables:
      # 指定某个表的分片配置,逻辑表名
      t_share_order:
        # 这个配置是告诉sharding有多少个库和多少个表及所在实际的数据库节点,由数据源名 + 表名组成(参考 Inline 语法规则)
        actualDataNodes: ds$->{
    
    1..2}.t_share_order
        # 配置库分片策略
        databaseStrategy:
          # 用于单分片键的标准分片场景
          standard:
            # 分片列名称
            shardingColumn: id
            # 分片算法名称
            shardingAlgorithmName: t_share_order_database_inline
        # 分布式序列策略
        keyGenerateStrategy:
          # 自增列名称,缺省表示不使用自增主键生成器
          column: id
          # 分布式序列算法名称
          keyGeneratorName: snowflake
    # 分片算法配置
    shardingAlgorithms:
      # 分片算法名称
      t_share_order_database_inline:
        # 分片算法类型
        type: INLINE
        # 分片算法属性配置
        props:
          algorithm-expression: ds$->{
    
    id % 2 + 1}
    # 分布式序列算法配置(如果是自动生成的,在插入数据的sql中就不要传id,null也不行,直接插入字段中就不要有主键的字段)
    keyGenerators:
      # 分布式序列算法名称
      snowflake:
        # 分布式序列算法类型
        type: SNOWFLAKE

props:
  sql-show: true #显示sql

shardingsphereデータシャーディングについては、公式 Web サイトを参照してください:
https://shardingsphere.apache.org/document/5.3.2/cn/user-manual/shardingsphere-jdbc/yaml-config/rules/sharding/

shardingsphere分散トランザクションのサポートについては、公式 Web サイトを参照してください: https://shardingsphere.apache.org/document/5.3.2/cn/user-manual/shardingsphere-jdbc/yaml-config/rules/transaction/

3.3 データソースの構成

sharding.yamlで構成されたデータ シャーディング ルールと使用されるトランザクション モードによりSeata AT、データ ソースは次のようになります。

3.3.1 ds1 テーブル作成ステートメント

create DATABASE db1;
user db1;

-- ----------------------------
-- Table structure for t_share_order
-- ----------------------------
DROP TABLE IF EXISTS `t_share_order`;
CREATE TABLE `t_share_order`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `commodity_code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `count` int NULL DEFAULT 0,
  `money` decimal(10, 2) NULL DEFAULT 0.00,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- 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 = utf8mb4 COMMENT ='AT transaction mode undo table';

3.3.2 ds2 テーブル作成ステートメント

create DATABASE db2;
user db2;

-- ----------------------------
-- Table structure for t_share_order
-- ----------------------------
DROP TABLE IF EXISTS `t_share_order`;
CREATE TABLE `t_share_order`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `commodity_code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `count` int NULL DEFAULT 0,
  `money` decimal(10, 2) NULL DEFAULT 0.00,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- 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 = utf8mb4 COMMENT ='AT transaction mode undo table';

3.4 関数の構築

3.4.1 スタートアップクラス

com/gm/seata/openfeign/OrderShardingDatabaseATApplication.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("com.gm.seata.openfeign.feign")
public class OrderShardingDatabaseATApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderShardingDatabaseATApplication.class, args);
    }
}

3.4.2 エンティティクラス

com/gm/seata/openfeign/entity/Order.java

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;

@Data
@TableName("t_share_order")
public class Order {
    
    

    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

    private String userId;

    private String commodityCode;

    private int count;

    private BigDecimal money;
}

予防:

  • ここは、次の論理テーブル名に対応します@TableName("t_share_order")sharding.yaml
  • フィールドuserIdの注釈は@TableId(type = IdType.ASSIGN_ID)、主キー生成戦略がmybatis-plus組み込みのスノーフレーク アルゴリズムを使用し、必要な型が であるがLong、そうではないことを示していますlong(戦略は有効になりませんid=0)。

3.4.3 マッパークラス

com/gm/seata/openfeign/mapper/OrderMapper.java

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gm.seata.openfeign.entity.Order;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface OrderMapper extends BaseMapper<Order> {
    
    

}

3.4.4 サービスクラス

com/gm/seata/openfeign/service/OrderService.java

public interface OrderService {
    
    

    /**
     * 创建订单
     *
     * @param userId
     * @param commodityCode
     * @param count
     * @return
     */
    boolean createOrder(String userId, String commodityCode, Integer count);
}

com/gm/seata/openfeign/service/impl/OrderServiceImpl.java

import com.gm.seata.openfeign.entity.Order;
import com.gm.seata.openfeign.feign.AccountServiceApi;
import com.gm.seata.openfeign.feign.StorageServiceApi;
import com.gm.seata.openfeign.mapper.OrderMapper;
import com.gm.seata.openfeign.service.OrderService;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    
    

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    StorageServiceApi storageServiceApi;

    @Autowired
    AccountServiceApi accountServiceApi;

    @Transactional
    /*@GlobalTransactional*/
    @Override
    public boolean createOrder(String userId, String commodityCode, Integer count) {
    
    

        String xid = RootContext.getXID();
        log.info("全局事务 xid:{}", xid);

        Order order = new Order();
        order.setCount(count);
        order.setCommodityCode(commodityCode);
        order.setUserId(userId);
        order.setMoney(new BigDecimal(count * 100.0));
        int i = orderMapper.insert(order);

        try {
    
    
            storageServiceApi.deduct(commodityCode, count);
        } catch (Exception e) {
    
    
            throw new RuntimeException(e.getMessage());
        }
        try {
    
    
            accountServiceApi.deduct(userId, new BigDecimal(count * 100.0));
        } catch (Exception e) {
    
    
            throw new RuntimeException(e.getMessage());
        }


        return i == 1;
    }
}

予防:

  • 分散トランザクションを有効にするには、呼び出しメソッドに注釈を追加する必要があります@Transactional現時点では、パターンのサポートが統合されているため、( ) -トランザクションマネージャーshardingsphereロールの呼び出しメソッドに注釈を追加することはできません。Seata ATTMTransaction Manager@GlobalTransactional

参考ソースコードorg.apache.shardingsphere.transaction.base.seata.at.SeataATShardingSphereTransactionManager

ここに画像の説明を挿入
ここに画像の説明を挿入

トランザクション マネージャーを介してトランザクションを開くとSeataATShardingSphereTransactionManager、既存のグローバル トランザクションが読み取られるか、新しいグローバル トランザクションが作成されるため、明示的に@GlobalTransactionalアノテーションを追加する必要はありません。

3.4.5 コントローラークラス

com/gm/seata/openfeign/controller/OrderController.java

import com.gm.seata.openfeign.service.OrderService;
import com.gm.seata.openfeign.util.ErrorEnum;
import com.gm.seata.openfeign.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class OrderController {
    
    

    @Autowired
    OrderService orderService;

    /**
     * 商品下单购买
     *
     * @param userId
     * @param commodityCode
     * @param count
     * @return
     */
    @RequestMapping(value = "buy", method = RequestMethod.GET)
    public R<String> buy(@RequestParam("userId") String userId, @RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count) {
    
    
        try {
    
    
            orderService.createOrder(userId, commodityCode, count);
            return R.ok("下单成功", "");
        } catch (Exception e) {
    
    
            e.printStackTrace();
            int code = Integer.parseInt(e.getMessage());
            return R.restResult("下单失败", code, ErrorEnum.getEnumByCode(code).getTitle());
        }
    }
}

4. テスト例

リクエストアドレス: http://127.0.0.1:3012/buy?userId=user1&count=2&commodityCode=iphone

リクエストごとに、残高から 200 元が差し引かれ、在庫が 2 つ差し引かれます。

4.1 グローバルトランザクションが正常に送信される

ここに画像の説明を挿入

4.2 グローバルトランザクションのロールバックが成功する

ここに画像の説明を挿入

このとき、t_share_orderログから該当するデータソースのテーブルを確認すると、新たなデータが追加されていないことがわかります。

おすすめ

転載: blog.csdn.net/ctwy291314/article/details/131487332