手把手带你一起搭建Seata,结合SpringCloud alibaba实战(二)

news2024/11/18 19:33:34

手把手带你一起搭建Seata,结合SpringCloud alibaba实战(二)

  • 前言
  • 具体实现
    • 大致流程
    • 配置微服务
    • 订单服务
    • 库存服务
  • 测试
    • 订单服务异常
    • 库存服务异常
  • 总结

接下来的一段时间论文解说要暂时放一放,咱们一起来了解下微服务方面的知识,欢迎大家来微服务专栏逛一逛,后续会慢慢更新使用教程以及源码等博客。感谢大家的支持!

前言

前面的博客手把手带你一起搭建Seata,结合SpringCloud alibaba实战(一)里咱们已经聊过了怎么搭建Seata,解析来我们看看SpringCloud Alibaba怎么结合Seata。

具体实现

大致流程

首先,我们需要将微服务与Seata连接一起。为了测试微服务之间的事务,我们需要两个微服务,即订单服务和库存服务。测试案例就是我们需要添加订单信息,然后需要减少库存,添加订单信息是在订单服务中完成的,减少库存则是在库存服务中完成的。

我们希望,两服务中一旦一方出现问题,就需要一起回滚。

需要注意的是,由于篇幅原因,接下来的代码中并不会列出数据库相关操作的代码,博主这里直接用的Mybaits-plus,大家可以试着写写,如果需要完整代码可以联系博主。

配置微服务

既然我们要连接Seata,那我们肯定首先需要配置Seata的ip啥的,对吧。

但是之前手把手带你一起搭建Seata,结合SpringCloud alibaba实战(一)提到了将Seata注册到Nacos中了,所以我们的配置就变得简单了,我们需要在订单和库存服务的application.yml中都添加以下配置。

seata:
  registry:
    type: nacos
    nacos:
    # Seata注册的应用名
      application: seata-server
      group: SEATA_GROUP
      # Nacos的ip和端口号
      server-addr: 192.168.241.139:8849
  config:
    type: nacos
    nacos:
    # Nacos的ip和端口号
      server-addr: 192.168.241.139:8849
      group: SEATA_GROUP

订单服务

Seata用起来也很简单,也就是直接加上@GlobalTransactional注解就可以了。这个接口是订单的接口,用于添加订单信息。

 	@GlobalTransactional
    @PostMapping("addOrder")
    public Result addOrder(Long id) {
            orderinfoService.save(new Orderinfo().setName(String.format("订单商品id:%s", id)));
            // 这里以OpenFegin的方式调用库存的接口
            Result reducestock = stockService.reducestock(id);
            int i = 1 / 0;
            return Result.succ("下单成功");
    }

用于调用库存服务接口的OpenFegin

package com.xiaow.fegin;

import com.xiaow.common.vo.Result;
import com.xiaow.fegin.impl.StockServiceImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "stock",fallback = StockServiceImpl.class)
public interface StockService {

    @PostMapping("/stockinfo/reducestock")
    Result reducestock(@RequestParam("id") Long id);


}

用来处理调用异常的StockServiceImpl

package com.xiaow.fegin.impl;

import com.xiaow.common.vo.Result;
import com.xiaow.fegin.StockService;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.tm.api.GlobalTransactionContext;
import org.springframework.stereotype.Component;

/**
 * @ClassName StockService
 * @Author xiaow
 * @DATE 2024/4/10 17:20
 **/


// 降级的类
@Component
public class StockServiceImpl implements StockService {

    @Override
    public Result reducestock(Long id) {
        return Result.fail("当前下单过于火爆,请稍后再试");
    }
}

库存服务

库存的接口,用于减少商品的库存

package com.xiaow.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaow.common.vo.Result;
import com.xiaow.entity.Stockinfo;
import com.xiaow.service.StockinfoService;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransactionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.math.BigInteger;
import java.util.List;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author xiaow
 * @since 2024-04-24
 */
@RestController
@RequestMapping("/stockinfo")
public class StockinfoController {

    @Autowired
    StockinfoService stockinfoService;

    @GetMapping("list")
    public Result list() {
        List<Stockinfo> list = stockinfoService.list();
        return Result.succ(list);
    }


    @PostMapping("reducestock")
    public Result reducestock(Long id) throws TransactionException {
        LambdaQueryWrapper<Stockinfo> stockinfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        stockinfoLambdaQueryWrapper.eq(Stockinfo::getId, id);
        Stockinfo one = stockinfoService.getOne(stockinfoLambdaQueryWrapper);
        if (one.getSize() > 0) {
            stockinfoService.update(new Stockinfo().setId(id).setSize(one.getSize() - 1), stockinfoLambdaQueryWrapper);
          
            return Result.succ("减库存成功");
        }


        return Result.succ("库存不足");

    }
}

测试

订单服务异常

接下来,上面可以看到,我们已经在订单接口中添加以下代码

int i = 1 / 0;

用来模拟订单服务异常。

咱们来看一下

初始状态订单是空的,商品数量是8。
在这里插入图片描述
在这里插入图片描述

我们运行一下
在这里插入图片描述
在这里插入图片描述

可以发现因为订单服务异常,订单信息并没有增加,库存数量也没变化,这证明确实事务生效了。

库存服务异常

那咱们看看远程调用的库存服务出现异常了,还可以吗

那就把订单接口的除0语句注释掉,然后在库存接口中添加除0语句来模拟服务异常。

订单接口

 	@GlobalTransactional
    @PostMapping("addOrder")
    public Result addOrder(Long id) {
        orderinfoService.save(new Orderinfo().setName(String.format("订单商品id:%s", id)));
        Result reducestock = stockService.reducestock(id);
//        int i = 1 / 0;
        return Result.succ("下单成功");
    }

库存接口

    @PostMapping("reducestock")
    public Result reducestock(Long id) throws TransactionException {
        LambdaQueryWrapper<Stockinfo> stockinfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        stockinfoLambdaQueryWrapper.eq(Stockinfo::getId, id);
        Stockinfo one = stockinfoService.getOne(stockinfoLambdaQueryWrapper);
        if (one.getSize() > 0) {
            stockinfoService.update(new Stockinfo().setId(id).setSize(one.getSize() - 1), stockinfoLambdaQueryWrapper);
            int i = 1 / 0;
            return Result.succ("减库存成功");
        }


        return Result.succ("库存不足");

    }

现在我们看下结果
在这里插入图片描述
在这里插入图片描述
不对呀,明明出现异常了,为什么没有回滚呢,这是咋回事

其实,这是因为咱们配置的Fegin的实现类帮咱们把库存接口的抛出的异常给处理了,因此Seata捕获不到异常,就以为啥事没有,所以就不会回滚。

那总不能说出异常了不管他吧,完全是可以处理的,就是在FeginServiceImpl中异常处理方法中添加以下内容即可

 GlobalTransactionContext.reload(RootContext.getXID()).rollback();

这时候就有小伙伴说了,难道写每一个异常处理方法的时候都要加这一句话吗,显然是不用的

别忘了咱有一个神奇的方法,叫做AOP,反正所有异常处理方法都要做这一件事,那我们干脆写个切面得了,一旦执行这些异常方法就直接回滚。

具体实现如下

package com.xiaow.aop.Aspect;

import com.xiaow.exception.SeataTransactionException;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.tm.api.GlobalTransactionContext;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @ClassName FeginSeataAspect
 * @Author xiaow
 * @DATE 2024/4/25 20:04
 * 对fegin拦截的错误进行回滚
 **/

@Aspect
@Component
public class FeginSeataAspect {
    @Pointcut("execution(* com.xiaow.fegin.*.*.*(..))")
    public void seataFallback() {

    }

    @After("seataFallback()")
    public void doAfter() {
        try {
            GlobalTransactionContext.reload(RootContext.getXID()).rollback();
            System.out.println("回滚了");
            throw new SeataTransactionException(-1);
        } catch (TransactionException e) {
            e.printStackTrace();
        }
    }
}

这样咱们再测试一下
在这里插入图片描述

在这里插入图片描述

ok,成功回滚

总结

这里只是做了一个简单的小案例,大家可以在此基础上完成具体的需求。最主要的点还是在于被调用方法出现异常的特殊处理。

今天就到这了
在这里插入图片描述

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

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

相关文章

Web-SpringBootWeb

创建项目 后面因为报错&#xff0c;所以我把jdk修改成22&#xff0c;仅供参考。 定义类&#xff0c;创建方法 package com.start.springbootstart.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotati…

使用nacos实现注册中心和配置中心

实现注册中心 在pom文件中导入 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> 在bootstrap.yml中写下如下配置 spring:application:name: c…

安卓中对象序列化面试问题及回答

1. 什么是对象的序列化&#xff1f; 答&#xff1a; 序列化是将对象转换为字节流的过程&#xff0c;以便将其存储在文件、数据库或通过网络传输。反序列化则是将字节流重新转换为对象的过程。 2. 为什么在 Android 开发中需要对象的序列化&#xff1f; 答&#xff1a; 在 An…

一些优雅的监控运维技巧

准备工作 安装 sysstat sudo apt install sysstat查看某个进程的cpu情况 pidstst -u -p 256432查看某个进程的RAM情况 pidstst -r -p 256432查看某个进程的IO情况 pidstst -d -p 256432查看某个进程下的线程执行情况 pidstst -t -p 256432查看指定PID的进程对应的可执行文件…

2024五一杯数学建模C题思路分享 - 煤矿深部开采冲击地压危险预测

文章目录 1 赛题选题分析 2 解题思路2.1 问题重述2.2 第一问完整思路2.2 二、三问思路更新 3 最新思路更新 1 赛题 C题 煤矿深部开采冲击地压危险预测 煤炭是中国的主要能源和重要的工业原料。然而&#xff0c;随着开采深度的增加&#xff0c;地应力增大&#xff0c;井下煤岩动…

前端开发攻略---用原生JS在网页中也能实现文本转语音

1、原理 语音合成 (也被称作是文本转为语音&#xff0c;英语简写是 tts) 包括接收 app 中需要语音合成的文本&#xff0c;再在设备麦克风播放出来这两个过程。 Web API中对此有一个主要控制接口 SpeechSynthesis&#xff0c;外加一些处理如何表示要被合成的文本 (也被称为 utte…

6.C++模板(超全)

// 【思考】代码截屏&#xff0c;用荧光笔标写注释 挺清晰的&#xff0c;虽然不太整齐了&#xff08;在文末有尝试这种方法~&#xff09;&#xff0c;就是感觉 // 注释没有那么突出和强调&#xff0c;友友们要不讨论一下&#xff0c;不知道你们看起来是什么感觉&#xff0c;我…

Python 与 TensorFlow2 生成式 AI(一)

原文&#xff1a;zh.annas-archive.org/md5/d06d282ea0d9c23c57f0ce31225acf76 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 序言 “想象力比知识更重要。” – 阿尔伯特爱因斯坦&#xff0c;《爱因斯坦关于宇宙宗教和其他见解与格言》&#xff08;2009&#xff09;…

安全再升级,亚信安慧AntDB数据库与亚信安全二次牵手完成兼容性互认证

日前&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧&#xff09;的产品与亚信科技&#xff08;成都&#xff09;有限公司&#xff08;简称&#xff1a;亚信安全&#xff09;再次携手&#xff0c;完成亚信安慧AntDB数据库与亚信安全IPoE接入认证系统…

【进程通信】用命名管道模拟server和client之间的通信

关于命名管道 当了解了匿名管道的通信机制只能用于具有血缘关系的进程之间时&#xff0c;似乎是出于本能的提出疑问–如果两个进程没有任何关系呢&#xff1f; 假如两个进程之间没有血缘关系&#xff0c;彼此进程就没法轻易拥有对方的文件资源&#xff0c;即不能看到同一份共…

C++Day 7 作业

1、lambda #include <iostream>using namespace std;int main() {int a 100;int b 90;int temp;auto fun [&]()mutable->int {temp a;ab;btemp;};fun();cout<<a<<endl;return 0; } 2、vector #include <iostream> #include <vector>…

Linux 第十七章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

Python 与 TensorFlow2 生成式 AI(三)

原文&#xff1a;zh.annas-archive.org/md5/d06d282ea0d9c23c57f0ce31225acf76 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第七章&#xff1a;使用 GAN 进行风格转移 神经网络在涉及分析和语言技能的各种任务中正在取得进步。创造力是人类一直占有优势的领域&…

探索潜力:中心化交易所平台币的对比分析

核心观点 平台币在过去一年里表现差异显著&#xff1a; 在过去的一年里&#xff0c;只有少数几个平台币如BMX、BGB和MX的涨幅超过了100%。相比之下&#xff0c;由于市值较高&#xff0c;BNB和OKB的涨幅相对较低。 回购和销毁机制在平台币价值中起决定性作用&#xff1a; 像M…

力扣刷题 63.不同路径 II

题干 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到…

【JS篇之】异常

前言&#xff1a;在代码编写过程中&#xff0c;最常遇到的就是程序异常。其实异常并非坏事&#xff0c;它可以让开发人员及时发现、定位到错误&#xff0c;提醒我们做正确的事情&#xff0c;甚至在某些时候&#xff0c;我们还会手动抛出异常。 1.异常的分类 在JS中&#xff0…

PotatoPie 4.0 实验教程(32) —— FPGA实现摄像头图像浮雕效果

什么是浮雕效果&#xff1f; 浮雕效果是一种图像处理技术&#xff0c;用于将图像转换为看起来像浮雕一样的效果&#xff0c;给人一种凸起或凹陷的立体感觉&#xff0c;下面第二张图就是图像处理实现浮雕效果。 不过这个图是用Adobe公司的PS人工P图实现的&#xff0c;效果比较…

http的basic 认证方式

写在前面 本文看下http的basic auth认证方式。 1&#xff1a;什么是basic auth认证 basic auth是一种http协议规范中的一种认证方式&#xff0c;即一种证明你就是你的方式。更进一步的它是一种规范&#xff0c;这种规范是这样子&#xff0c;如果是服务端使用了basic auth认证…

UnityWebGL使用sherpa-ncnn实时语音识别

k2-fsa/sherpa-ncnn&#xff1a;在没有互联网连接的情况下使用带有 ncnn 的下一代 Kaldi 进行实时语音识别。支持iOS、Android、Raspberry Pi、VisionFive2、LicheePi4A等。 (github.com) 如果是PC端可以直接使用ssssssilver大佬的 https://github.com/ssssssilver/sherpa-ncn…

Mybatis进阶(动态SQL)

文章目录 1.动态SQL1.基本介绍1.为什么需要动态SQL2.基本说明3.动态SQL常用标签 2.环境搭建1.新建子模块2.删除不必要的两个文件夹3.创建基本结构4.父模块的pom.xml5.jdbc.properties6.mybatis-config.xml7.MyBatisUtils.java8.MonsterMapper.java9.MonsterMapper.xml10.测试Mo…