当前位置: 首页 > article >正文

2.Seata 1.5.2 集成Springcloud-alibaba

一.Seata-server搭建已完成前提下

详见 Seata-server搭建

二.Springcloud 项目集成Seata

项目整体测试业务逻辑是创建订单后(为了演示分布式事务,不做前置库存校验),再去扣减库存。库存不够的时候,创建的订单信息数据也会回退。

2.1 springboot,springcloud,springboot,seata项目版本的版本管理pom配置

    <!-- 统一依赖版本管理 -->
    <properties>
        <spring.boot.version>2.6.11</spring.boot.version>
        <spring-cloud.version>2021.0.4</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
        <seata.version>1.5.2</seata.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
                <exclusions>
                    <exclusion>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

2.2 Porduct项目seata核心依赖和配置及代码和undolog表初始化

基本的web,持久化,数据库,数据配置中心,注册中心依赖此处略。
核心pom.xml如下:

        <!--seata 分布式事务组件-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>

appliction.yml 核心配置如下:

# 端口
server:
  port: 8050
  servlet:
    context-path: /productApi

spring:
  application:
    name: dolphin-jinyi-product
  profiles:
    active: dev
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  main:
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      # 注册中心
      discovery:
        server-addr: localhost:8848
        namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
        group: DOLPHIN_GROUP
      # 配置中心
      config:
        server-addr: localhost:8848
        file-extension: yml
        group: DOLPHIN_GROUP
        namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
        # 这里可以配置多个共享配置文件
        shared-configs:
          - data-id: mysql-common.yml
            group: DEFAULT_GROUP
            refresh: true
          - data-id: redis-common.yml
            group: DEFAULT_GROUP
            refresh: true
logging:
  level:
    io:
      seata: INFO
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

seata:
  registry:
    # 配置seata的注册中心, 告诉seata client 怎么去访问seata server(TC)
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848  # seata server 所在的nacos服务地址
      application: seata-server    # seata server 的服务名seata-server ,如果没有修改可以不配
      username: nacos
      password: nacos
      group: DOLPHIN_GROUP             # seata server 所在的组,默认就是SEATA_GROUP,没有改也可以不配
      namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      group: DOLPHIN_GROUP             # seata server 所在的组,默认就是SEATA_GROUP,没有改也可以不配
      namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
      #指定Nacos上的DataId
      data-id: seata-server.yml
  tx-service-group: default_tx_group  #这里每个服务都是对应不同的映射名,在配置中心可以看到 事务分组,必须和服务器配置一样
  service:
    vgroup-mapping:
      default_tx_group: default
    grouplist:
      default: localhost:8091

java核心伪代码示例:

 */
@RestController
@RequestMapping("/product")
@Api(value = "商品Api", tags = {"商品Api"})
public class ProductController {

    @Resource
    private IProductService productService;

    @PostMapping("updateProductStock")
    @ApiOperation(value = "updateProductStock-更新商品库存", notes = "updateProductStock-更新商品库存")
    public R updateProductStock(@RequestParam(value = "productId") Integer productId,@RequestParam(value = "num")  Integer num) {
        productService.updateProductStock(productId,num);
        return R.ok();
    }
}
public interface IProductService extends IService<Product> {
    void updateProductStock(Integer productId, Integer num);
}

注:核心点在于根据产品id扣减库存的方法上需要分支事务 @Transactional(rollbackFor = Exception.class)注解。

@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProductStock(Integer productId, Integer num) {
        System.out.println("事务id---------------------->" + RootContext.getXID());
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<Product>()
                .eq(Product::getProductId, productId)
                .eq(Product::getStatus, 1).last("limit 1");
        Product product = this.getOne(queryWrapper);
        if (Objects.isNull(product)) {
           //商品不存在时抛异常
            throw new BizException(ResultCodeEnum.DATA_NOT_FOUND);
        }
        Integer stockNum = product.getStockNum() + num;
        if (stockNum < 0) {
            //库存不足时,抛异常
            throw new BizException(ResultCodeEnum.PRODUCT_STOCK_NOT_ENOUGH);
        }
        product.setStockNum(stockNum);
        this.updateById(product);
    }
}

在product项目对应的数据库中初始化undo_log表

CREATE TABLE `undo_log` (
  `branch_id` bigint(20) 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`),
  KEY `ix_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AT transaction mode undo table';

2.3 Order项目seata核心依赖和配置及代码和undolog表初始化

基本的web,持久化,数据库,数据配置中心,注册中心依赖此处略。
核心pom.xml如下:

        <!--seata 分布式事务组件-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>

appliction.yml 核心配置如下:

# 端口
server:
  port: 8010
  servlet:
    context-path: /orderApi

spring:
  application:
    name: dolphin-jinyi-order
  profiles:
    active: dev
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  main:
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      # 注册中心
      discovery:
        server-addr: localhost:8848
        namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
        group: DOLPHIN_GROUP
      # 配置中心
      config:
        server-addr: localhost:8848
        file-extension: yml
        group: DOLPHIN_GROUP
        namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
        # 这里可以配置多个共享配置文件
        shared-configs:
          - data-id: redis-common.yml
            group: DEFAULT_GROUP
            refresh: true

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
seata:
  registry:
    # 配置seata的注册中心, 告诉seata client 怎么去访问seata server(TC)
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848  # seata server 所在的nacos服务地址
      application: seata-server    # seata server 的服务名seata-server ,如果没有修改可以不配
      username: nacos
      password: nacos
      group: DOLPHIN_GROUP             # seata server 所在的组,默认就是SEATA_GROUP,没有改也可以不配
      namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      group: DOLPHIN_GROUP             # seata server 所在的组,默认就是SEATA_GROUP,没有改也可以不配
      namespace: d6eccad6-681c-4133-b9ff-1abcd951297a
        #指定Nacos上的DataId
      data-id: seata-server.yml
  tx-service-group: default_tx_group  #这里每个服务都是对应不同的映射名,在配置中心可以看到
  service:
    vgroup-mapping:
      default_tx_group: default
    grouplist:
      default: localhost:8091

java核心伪代码示例:

@RestController
@RequestMapping("/order")
@Api(value = "订单Api", tags = {"订单Api"})
public class OrderController {

    @Resource
    private IOrderService orderService;

    @ApiOperation(value = "createOrder-创建订单", notes = "createOrder-创建订单")
    @PostMapping("/createOrder")
    public R<Long> createOrder(@RequestBody @Validated OrderCreateDTO orderCreateDTO) {
        Long orderNo = orderService.createOrder(orderCreateDTO);
        return R.ok(orderNo);
    }
}
public interface IOrderService extends IService<Order> {
    Long createOrder(OrderCreateDTO orderCreateDTO);
}

注:核心注解 @GlobalTransactional

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Resource
    private ProductServiceFeignClient productServiceFeignClient;


    public Long createOrderNo() {
        return IdUtil.getSnowflakeNextId();
    }

    @Override
    @GlobalTransactional
    public Long createOrder(OrderCreateDTO orderCreateDTO) {
        System.out.println("事务id---------------------->" + RootContext.getXID());
        Order order = new Order();
        BeanUtil.copyProperties(orderCreateDTO, order);
        order.setOrderNo(this.createOrderNo());
        //创建订单
        this.insertOrder(order);
        //通过feign调用商品服务扣减库存
        productServiceFeignClient.updateProductStock(order.getProductId(), -1);
        return order.getOrderNo();
    }

    @Transactional(rollbackFor = Exception.class)
    public void insertOrder(Order order) {
        System.out.println("事务id A---------------------->" + RootContext.getXID());
        boolean save = this.save(order);
        if (!save) {
            throw new BizException(ResultCodeEnum.SYSTEM_EXECUTION_ERROR);
        }
    }

}

在order项目对应的数据库中初始化undo_log表

CREATE TABLE `undo_log` (
  `branch_id` bigint(20) 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`),
  KEY `ix_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AT transaction mode undo table';

三.设计到的nacos中的seata-server.yml等配置

注意上面项目的yml配置中的namespace,groupId,data-id 保持和nacos一直
在这里插入图片描述
seata-server.yml

service:
  vgroupMapping:
    default_tx_group: default

四 测试

测试时,保证seata-server order product 服务都已经启动。
现在库存有一个,没有订单信息数据。
在这里插入图片描述
在这里插入图片描述

4.1 第一次下单
在这里插入图片描述
商品表库存被扣减,创建订单成功
在这里插入图片描述
在这里插入图片描述
现在库存为0.第二次下单
在这里插入图片描述
订单没有新增,库存也没有扣减。分布式事务测试ok
在这里插入图片描述
在这里插入图片描述


http://www.kler.cn/a/319501.html

相关文章:

  • 【真题笔记】21年系统架构设计师案例理论点总结
  • 深入理解接口测试:实用指南与最佳实践5.0(一)
  • vue3 pdf base64转成文件流打开
  • 后端接口返回二进制文件,前端 window.opent预览展示
  • 自动驾驶3D目标检测综述(一)
  • 【Linux篇】面试——用户和组、文件类型、权限、进程
  • 【算法】贪心+堆排序实现大根堆及标准库容器类的融合使用
  • python 2024-10
  • Angular面试题八
  • 13.第二阶段x86游戏实战2-动态模块地址
  • Unicode编码如何转换为汉字
  • DAY78服务攻防-数据库安全RedisCouchDBH2database未授权访问CVE 漏洞
  • 仓颉编程入门2,启动HTTP服务
  • 基于数据挖掘的航空客户满意度分析预测系统
  • 安卓系统常见问题如native crash,卡顿卡死定位工具命令技巧-android framework实战开发
  • Java_Day05学习
  • 搜维尔科技:通过xsens动作捕捉为影视角色注入生命
  • 前端框架的对比和选择
  • MySQL备份与恢复详解
  • Anaconda/Miniconda的删除和安装
  • rapidocr 提取汇总
  • 可以写自动化测试工具的AI工具
  • [笔记]交流接触器
  • UR机器人坐标系转化
  • C++系列-Stackqueue
  • Qt中多语言的操作(以QtCreator为例)