2.Seata 1.5.2 集成Springcloud-alibaba

news2024/11/14 15:03:40

一.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.coloradmin.cn/o/2152134.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

攻防世界Web新手练习区题目(view_source到simple_php)WP

目录 view_source​ robots​ Training-WWW-Robots PHP2​ get_post​ backup​ cookie​ disabled_button​ simple_js​ xff_referer​ weak_auth​ command_execution​ simple_php​ view_source 获取在线场景后访问题目场景 在右键不管用的情况下&#xff0…

尚品汇-秒杀成功下单接口、秒杀结束定时任务-清空缓存数据(五十四)

目录&#xff1a; &#xff08;1&#xff09;下单页面 &#xff08;2&#xff09;service-activity-client添加接口 &#xff08;3&#xff09;web-all 编写去下单控制器 &#xff08;4&#xff09;service-order模块提供秒杀下单接口 &#xff08;5&#xff09;service-or…

1份可以派上用场丢失数据恢复的应用程序列表

无论如何&#xff0c;丢失您的宝贵数据是可怕的。您的 Android 或 iOS 设备可能由于事故、硬件损坏、存储卡问题等而丢失了数据。这就是为什么我们编制了一份可以派上用场以恢复丢失数据的应用程序列表。 如果您四处走动&#xff0c;您大多会随身携带手机或其他移动设备。这些…

豆包Python SDK接入流程

模型与价格 豆包的模型介绍可以看豆包大模型介绍&#xff0c;模型价格可以看豆包定价文档里的“模型推理” - “大语言模型” - “字节跳动”部分。 推荐使用以下模型&#xff1a; Doubao-lite-32k&#xff1a;每百万 token 的输入价格为 0.3 元&#xff0c;输出价格为 0.6 元…

vue组件($refs对象,动态组件,插槽,自定义指令)

一、ref 1.ref引用 每个vue组件实例上&#xff0c;都包含一个$refs对象&#xff0c;里面存储着对应dom元素或组件的引用。默认情况下&#xff0c;组件的$refs指向一个空对象。 2.使用ref获取dom元素的引用 <template><h3 ref"myh3">ref组件</h3&g…

手机切换IP简单方法:掌握技巧,轻松实现IP变换‌

在当今的数字化时代&#xff0c;IP地址作为网络身份的重要标识&#xff0c;对于网络访问、数据传输等方面都起着至关重要的作用。然而&#xff0c;在某些特定场景下&#xff0c;我们可能需要切换手机的IP地址&#xff0c;以满足不同的网络需求。本文将为大家介绍几种手机切换IP…

Linux —— 多线程

一、本篇重点 1.了解线程概念&#xff0c;理解线程与进程区别与联系 2.理解和学会线程控制相关的接口和操作 3.了解线程分离与线程安全的概念 4.学会线程同步。 5.学会互斥量&#xff0c;条件变量&#xff0c;posix信号量&#xff0c;以及读写锁 6.理解基于读写锁的读者写…

Kafka 3.0.0集群部署教程

1、集群规划 主机名 ip地址 node.id process.roles kafka1 192.168.0.29 1 broker,controller Kafka2 192.168.0.30 2 broker,controller Kafka3 192.168.0.31 3 broker,controller 将kafka包上传以上节点/app目录下 mkdir /app 解压kafka包 tar -zxvf kafka_…

BLE 协议之链路层

目录 一、前言二、状态和角色三、Air Interface Packets1、Preamble 字段2、Access Address 字段2.1 静态地址2.2 私有地址 3、PDU 字段3.1 Advertising Channel PDU3.1.1 Header 字段3.1.2 Payload 字段 3.2 Data Channel PDU3.2.1 Header 字段3.2.2 Payload 字段 4、CRC 字段…

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第一篇-原理】

如果想直接制作&#xff0c;请看【第二篇】内容 这次做一个这样的东西&#xff0c;通过在2DRT上实时绘制&#xff0c;生成动态的体积纹理&#xff0c;也就是可以runtime的VDB 设想的文章流程: 对原理进行学习制作体积渲染制作实时绘制 第一篇&#xff08;本篇&#xff09;是对“…

Spring MVC 基础 : 文件、cookies的接收 ,REST响应

一、接受文件 在 Spring MVC 中&#xff0c;可以使用 RequestPart 注解来接收文件。这个注解常用于处理复杂的请求&#xff0c;如同时发送 JSON 数据和文件。RequestPart 非常适用于多部分请求&#xff08;multipart requests&#xff09;&#xff0c;这在单个请求中同时发送文…

法定退休年龄计算器,看看你还有多少年退休?

最近延迟退休上了微博热搜&#xff0c;从2025年开始实行。 分享个法定退休年龄计算器&#xff0c;看看你还有多少年退休&#xff1f; 官方出品的计算器&#xff0c;网站地址 https://si.12333.gov.cn/304647.jhtml 输入出生日期和性别就可以。 当然也可以在微信的城市服务。…

基于asp.net固定资产管理系统设计与实现

博主介绍&#xff1a;专注于Java vue .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的…

JZ2440开发板——S3C2440的UART

以下内容源于韦东山课程的学习与整理&#xff0c;如有侵权请告知删除。 一、UART硬件简介 UART&#xff0c;全称是“Universal Asynchronous Receiver Transmitter”&#xff0c;即“通用异步收发器”&#xff0c;也就是我们日常说的“串口”。 它在嵌入式中用途非常广泛&…

【计算机网络篇】物理层

本文主要介绍计算机网络第二章节的物理层&#xff0c;文中的内容是我认为的重点内容&#xff0c;并非所有。参考的教材是谢希仁老师编著的《计算机网络》第8版。跟学视频课为河南科技大学郑瑞娟老师所讲计网。 文章目录 &#x1f3af;一.基本概念及公式 &#x1f383;基本概念…

力扣-1035不相交的线(Java详细题解)

题目链接&#xff1a;力扣-1035不相交的线 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5.如果没有ac打印dp数组 利于debug。 每一…

安全基础学习-AES128加密算法

前言 AES&#xff08;Advanced Encryption Standard&#xff09;是对称加密算法的一个标准&#xff0c;主要用于保护电子数据的安全。AES 支持128、192、和256位密钥长度&#xff0c;其中AES-128是最常用的一种&#xff0c;它使用128位&#xff08;16字节&#xff09;的密钥进…

充电宝什么品牌比较好?五大性价比高充电宝品牌推荐!

在这个电子设备无处不在的时代&#xff0c;充电宝已成为我们生活中不可或缺的重要配件。无论是通勤、旅行还是户外休闲&#xff0c;充电宝都能为我们的手机、平板等提供及时的电量补充&#xff0c;确保我们时刻保持在线。一个安全可靠的充电宝&#xff0c;不仅能为我们的设备提…

GRU(门控循环单元)的原理与代码实现

1.GRU的原理 1.1重置门和更新门 1.2候选隐藏状态 1.3隐状态 2. GRU的代码实现 #导包 import torch from torch import nn import dltools#加载数据 batch_size, num_steps 32, 35 train_iter, vocab dltools.load_data_time_machine(batch_size, num_steps)#封装函数&…

VScode开发GD32移植(标准库通用),保姆级!!!!!!!

VScode开发GD32移植(标准库通用)&#xff0c;保姆级&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 文章目录 VScode开发GD32移植(标准库通用)&#xff0c;保姆级&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#…