SpringCloud之Seata(二)

news2024/12/21 10:38:52

4.Seata如何应用于项目?

安装seata及修改配置

4.1 官网下载Seata安装包

4.2 修改seata/config.txt

4.2.1 修改存储方式

store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://你的IP:3306/seata?useUnicode=true
store.db.user=root
store.db.password=root

4.2.2 添加如下配置

service.vgroupMapping.demo-order=default
service.vgroupMapping.demo-storage=default
service.vgroupMapping.demo-account=default

4.3 修改seata/conf/registry.conf

4.3.1 注册中心改为nacos

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "你的IP:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }

4.3.2 配置中心也改为nacos

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "你的IP:8848"
    namespace = "在nacos中创建一个命名空间,用来保存seata配置,提前配置好"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }

4.4 执行nacos脚本,推送seata配置到nacos

sh nacos-config.sh -h 你的nacos -p 8848 -g SEATA_GROUP -t 上面创建的命名空间 -u nacos -w nacos

创建seata需要用到的表

4.4.1 创建数据库

create database seata;

4.4.2 创建相关表

global_table: 全局事务表,每当有一个全局事务发起后,就会在该表中记录全局事务的ID

branch_table: 分支事务表,记录每一个分支事务的 ID,分支事务操作的哪个数据库等信息

lock_table: 全局锁

CREATE TABLE `branch_table` (
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `resource_group_id` varchar(32) DEFAULT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `branch_type` varchar(8) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  `client_id` varchar(64) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime(6) DEFAULT NULL,
  `gmt_modified` datetime(6) DEFAULT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `global_table` (
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `application_id` varchar(32) DEFAULT NULL,
  `transaction_service_group` varchar(32) DEFAULT NULL,
  `transaction_name` varchar(128) DEFAULT NULL,
  `timeout` int(11) DEFAULT NULL,
  `begin_time` bigint(20) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`xid`),
  KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
  KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `lock_table` (
  `row_key` varchar(128) NOT NULL,
  `xid` varchar(96) DEFAULT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `branch_id` bigint(20) NOT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `table_name` varchar(32) DEFAULT NULL,
  `pk` varchar(36) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`row_key`),
  KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

启动seata服务

sh seata/bin/seata-server.sh 启动成功后,监听8091端口

在这里插入图片描述

看下nacos中是否注册了此服务: 看到如下内容表示,seata已经安装并注册成功

在这里插入图片描述

项目整合seata

1. 创建父工程
在ams-demo下创建父工程demo-seata,并修改父工程打包方式为pom

2. 添加依赖


<dependencies>
        <!-- 配置读取 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Spring Cloud & Alibaba -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

        <!-- 注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!-- 配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>com.ams</groupId>
            <artifactId>common-mybatis-plus</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.ams</groupId>
            <artifactId>common-base</artifactId>
            <version>${ams.version}</version>
        </dependency>

        <dependency>
            <groupId>com.ams</groupId>
            <artifactId>common-web</artifactId>
            <version>${ams.version}</version>
        </dependency>

        <!-- openfeign依赖 1. http客户端选择okhttp 2. loadbalancer替换ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
        <!--seata 必备-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
    </dependencies>

4.4.3 创建订单子模块(库存、账户子模块类似)

1. 在demo-seata下创建demo-order子模块

2. 添加创建订单的接口

/**
 * @description:创建订单控接口
 */
@RestController
@RequestMapping("/order")
@RequiredArgsConstructor
public class OrderController {
    private final OrderService orderService;

    @RequestMapping("/createOrder")
    public R createOrder() {
        orderService.createOrder();
        return R.ok("订单创建成功");
    }
}

3. 添加创建订单的service


/**
 * @description:创建订单service
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    private final AccountFeignService accountFeignService;
    private final StorageFeignService storageFeignService;

    @Override
    @GlobalTransactional(name = "ams-create-order",rollbackFor = Exception.class)
    public R createOrder() {
        Order order = Order.builder()
                .count(10)
                .money(100)
                .productId(1L)
                .status(0)
                .userId(1L)
                .build();
        // 创建订单
        save(order);
        // 扣除库存
        storageFeignService.decrease(order.getProductId(), order.getCount());
        // 扣余额
        accountFeignService.decrease(order.getUserId(), order.getMoney());
        //更新订单状态
        order.setStatus(1);
        updateById(order);
        return R.ok();
    }
}

4. 添加调用库存接口的feign

/**
 * Description:调用库存接口的feign

 */
@FeignClient(value = "ams-demo-storage")
@RequestMapping("/storage")
public interface StorageFeignService {
    @RequestMapping("/decrease")
    public R decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}

5. 添加调用账户接口的feign

/**
 * Description:调用账户接口的feign
 */
@FeignClient(value = "ams-demo-account")
@RequestMapping("/account")
public interface AccountFeignService {
    @RequestMapping("/decrease")
    public R decrease(@RequestParam("userId") Long userId, @RequestParam("money") Integer money);
}

6. 创建启动类

/**
 * @description:订单启动类
 */
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@EnableFeignClients
public class DemoOrderApp {
    public static void main(String[] args) {
        SpringApplication.run(DemoOrderApp.class, args);
    }
}

7. 创建bootstrap.yml

server:
  port: 20003

spring:
  application:
    name: ams-demo-order
  cloud:
    nacos:
      # 注册中心
      discovery:
        server-addr: http://你的nacos地址:8848
      # 配置中心
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yaml
        shared-configs[0]:
          data-id: ams-common.yaml
          refresh: true
    alibaba:
      seata:
        tx-service-group: demo-order

8. 新增nacos配置:

在naocs中创建ams-demo-order.yaml配置


spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver 
    url: jdbc:mysql://${mysql.host}:${mysql.port}/ams_order?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true
    username: ${mysql.username}
    password: ${mysql.password}
  redis:
    database: 0
    host: ${redis.host}
    port: ${redis.port}
    password: ${redis.password}
  cache:
    # 缓存类型
    type: redis
    # 缓存时间(单位:ms)
    redis:
      time-to-live: 3600000
      # 缓存null值,防止缓存穿透
      cache-null-values: true
      # 允许使用缓存前缀,
      use-key-prefix: true
      # 缓存前缀,没有设置使用注解的缓存名称(value)作为前缀,和注解的key用双冒号::拼接组成完整缓存key
      key-prefix: 'admin:'
                
mybatis-plus:
  configuration:
    # 驼峰下划线转换
    map-underscore-to-camel-case: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

# 全局参数设置
ribbon:
  ReadTimeout: 120000
  ConnectTimeout: 10000
  SocketTimeout: 10000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1 

feign:
  httpclient:
    enabled: true
  okhttp:
    enabled: false
#Seata分布式事务配置(AT模式)
seata:
  enabled: true
  application-id: ${spring.application.name}
  #客户端和服务端在同一个事务组
  tx-service-group: demo-order
  enable-auto-data-source-proxy: true
  service:
    vgroup-mapping:
      demo-order: default
  config:
    type: nacos
    nacos:
      namespace: "填写在安装seata时创建的命名空间"
      serverAddr: 你的nacos ip:8848
      group: SEATA_GROUP
      username: "nacos"
      password: "nacos"
  #服务注册到nacos
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 你的nacos ip:8848
      group: SEATA_GROUP
      namespace: "public"
      username: "nacos"
      password: "nacos"
      cluster: default
logging:
  level:
    spring: info

9. 创建回滚表

在每个业务数据库下面创建回滚表


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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='AT transaction mode undo table';

10. 验证

启动三个服务,请求:http://localhost:20003/order/createOrder,通过设置异常,观察是否全局回滚 ​





上一篇跳转—SpringCloud之Seata(一)



本文主要参考链接:
SpringCloud实战|8.SpringCloud 整合 seata1.3-估计是全网讲的最细的并且一次成功的



随心所往,看见未来。Follow your heart,see light!

欢迎点赞、关注、留言,收藏及转发,一起学习、交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/371311.html

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

相关文章

第一篇博客------自我介绍篇

目录&#x1f506;自我介绍&#x1f506;学习目标&#x1f506;如何学习单片机Part 1 基础理论知识学习Part 2 单片机实践Part 3 单片机硬件设计&#x1f506;希望进入的公司&#x1f506;结束语&#x1f506;自我介绍 Hello!!!我是一名即已经步入大二的计算机小白。 --------…

F4—LVDS接口LCD显示彩图测试-2023-02-25

1.简介 系列文章TFT彩条测试介绍到&#xff0c;屏幕是由厂家提供的TFT显示模组和屏幕PCB背板组成。PCB的作用是提供LCD背光所需的电压、用于屏幕显示的电压、与其他设备相连的排针或者其他连接器形式。当模组支持触摸功能时还可以接上触摸转换或触摸控制芯片&#xff0c;通过SP…

Qt 中的XML

XML的基本介绍&#xff1a; 在前端开发中&#xff1a;HTML是用来显示数据&#xff0c;而XML是用来传输和存储数据的 XML 指可扩展标记语言&#xff08;EXtensible Markup Language&#xff09;XML 是一种标记语言&#xff0c;很类似 HTMLXML 的设计宗旨是传输数据&#xff0c;而…

超简单的待办事项列表管理器todo

什么是 todo ? todo 是一个自托管的 todo web 应用程序&#xff0c;可让您以简单且最少的方式跟踪您的 todo。&#x1f4dd; 老苏觉得和之前介绍的 KissLists 比较像 文章传送门&#xff1a;最简单的共享列表服务器KissLists 官方提供了 Demo 演示站点&#xff1a;https://tod…

零基础的人如何入门 Python ?看完这篇文章你就懂了

第一部分&#xff1a;编程环境准备 零基础入门Python的话我不建议用IDE&#xff0c;IDE叫集成开发环境&#xff0c;这东西一般是专业程序员用来实战开发用的&#xff0c;好处很多&#xff0c;比如&#xff1a;调试、语法高亮、项目管理、代码跳转、智能提示、自动完成、单元测…

Android-MVVM之快速上手ViewModel

Android-MVVM之快速上手ViewModel什么是ViewModel&#xff1f;ViewModel生命周期&#xff1f;ViewModel的使用&#xff1f;什么是ViewModel&#xff1f; 简单来说&#xff0c;就是让view层(视图层)与model层(数据层)分离开来的桥梁。让view层展示ui&#xff0c;不持有数据。 Vi…

【2021春节】解题领红包之番外篇

【2021春节】解题领红包之番外篇前言原始代码解题思路flag1寻找flag2的寻找前言 记录下jsfuck的另类&#xff0c;时间都过去两年了&#xff0c;确实有点久远。。。 原始代码 要求找出flag1和flag2值 ([][])[([][[]][])[!![]](!![][][(![][])[[]](![][])[!![]!![]](![][])[!![…

Vue基础入门讲义(二)-语法基础

文章目录1.vue入门案例1.1.HTML模板1.2.vue渲染1.3.双向绑定1.4.事件处理2.Vue实例2.1.创建Vue实例2.2.模板或元素2.3.数据2.4.方法3.生命周期钩子3.1.生命周期3.2.钩子函数3.3.this1.vue入门案例 1.1.HTML模板 在项目目录新建一个HTML文件 01-demo.html 1.2.vue渲染 01-d…

SSM框架-AOP概述、Spring事务

16 spring整合mybatis 16.1 前情代码 实体类 public class Account {private Integer id;private String name;private Double money;public Integer getId() {return id;}public void setId(Integer id) {this.id id;}public String getName() {return name;}public void …

搭建k8s高可用集群—20230225

文章目录多master&#xff08;高可用&#xff09;介绍高可用集群使用技术介绍搭建高可用k8s集群步骤1. 准备环境-系统初始化2. 在所有master节点上部署keepalived3.1 安装相关包3.2 配置master节点3.3 部署haproxy错误解决3. 所有节点安装Docker/kubeadm/kubelet4. 部署Kuberne…

对redis之键值型数据库的理解

键值数据库&#xff0c;首先就要考虑里面可以存什么样的数据&#xff0c;对数据可以做什么样的操作&#xff0c;也就是数据模型和操作接口。它们看似简单&#xff0c;实际上却是我们理解 Redis 经常被用于缓存、秒杀、分布式锁等场景的重要基础。理解了数据模型&#xff0c;你就…

2022年网络安全竞赛——数字取证调查attack.pcapng

攻击日志分析:需求环境可私信博主获取 任务环境说明: 服务器场景:PYsystem0031服务器场景操作系统:未知服务器场景FTP用户名:anonymous 密码:空从靶机服务器的FTP上下载attack.pcapng数据包文件,通过分析数据包attack.pcapng,找出黑客的IP地址,并将黑客的IP地址作为FL…

SPI协议介绍

SPI协议介绍 文章目录SPI协议介绍一、 SPI硬件知识1.1 硬件连线1.2 SPI控制器内部结构二、 SPI协议2.1 传输示例2.2 SPI模式致谢一、 SPI硬件知识 1.1 硬件连线 引脚含义如下&#xff1a; 引脚含义DO(MOSI)Master Output, Slave Input&#xff0c;SPI主控用来发出数据&#x…

逆向之Windows PE结构

写在前面 对于Windows PE文件结构&#xff0c;个人认为还是非常有必要掌握和了解的&#xff0c;不管是在做逆向分析、免杀、病毒分析&#xff0c;脱壳加壳都是有着非常重要的技能。但是PE文件的学习又是一个非常枯燥过程&#xff0c;希望本文可以帮你有一个了解。 PE文件结构…

buu [NCTF2019]babyRSA 1

题目描述&#xff1a; 题目分析&#xff1a; 首先明确两个公式&#xff1a; e*d 1 mod (p-1)(q-1) ed1 e*d - 1 k(p-1)(q-1)想要解出此题&#xff0c;我们必须知道n,而要知道n,我们要知道p和q的值通过 e*d 的计算&#xff0c;我们知道其长度为2066位&#xff0c;而生成p的…

《分布式技术原理与算法解析》学习笔记Day22

哈希与一致性哈希 在分布式系统中&#xff0c;哈希和一致性哈希是数据索引或者数据分布的常见实现方式。 数据分布设计原则 在分布式数据存储系统中&#xff0c;做存储方案选型时&#xff0c;一般会考虑以下因素&#xff1a; 数据均匀数据稳定节点异构性隔离故障域性能稳定…

Delphi Http Https 最好的解决方法(三) LoadLibrary扩展

开发环境: Delphi XE 10.1 Berlin 前提文章: Delphi Http Https 最好的解决方法(二) 目录 1. 项目描述 2. 问题描述 3. 解决方案 3.1 主程序在导入dll方法单元处理(不推荐) 3.2 在dll的工程文件处加入(不推荐) 3.3 在dll的工程文件获取dll(HelpTool.dll)的当前路径(推荐方…

gitlab 安装到项目上传一篇解决

文章目录1.安装1.1创建挂载目录1.2启动1.3 配置gitlab查看docker admin 账户初始密码注册普通用户2.1进入注册2.2创建后通过登录admin审批3.2 步骤13.2 步骤23.3步骤33.4 项目添加成员4 使用成员用户,上传到新建的项目中4.1 复制项目地址4.2使用 git here 克隆项目4.3进入下载目…

读懂分布式事务

一、概述 1.1 什么是分布式事务 事务我们都很熟悉&#xff0c;事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元&#xff0c;组成这组操作的各个单元&#xff0c;要么全部成功&#xff0c;要么全部失败。 事务有四大特性&#xff1a; Atomic&#xf…

rabbitmq安装和thinkphp6简单操作思路

1、安装rabbitmq 2、crontab定时检测rabbtimq状态 2、使用thinphp6.0框架rabbitmq示例,supervisor守护消费者 3、RabbitMQ有四种交换机类型 rabbitmq组成部分如下&#xff1a; Broker&#xff1a;消息队列服务进程&#xff0c;此进程包括两个部分&#xff1a;Exchange和Que…