微服务框架 SpringCloud微服务架构 分布式事务 38 动手实践 38.8 案例实现TCC 模式【实现】

news2024/11/28 0:39:12

微服务框架

【SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】

分布式事务

文章目录

      • 微服务框架
      • 分布式事务
      • 38 动手实践
        • 38.8 案例实现TCC 模式【实现】
          • 38.8.1 声明TCC 接口

38 动手实践

38.8 案例实现TCC 模式【实现】

38.8.1 声明TCC 接口

TCC的Try、Confirm、Cancel方法都需要在接口中基于注解来声明,语法如下:

在这里插入图片描述

直接试试

在account-service 中

新创建接口

package cn.itcast.account.service;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

/**
 * ClassName: AccountTCCService
 * date: 2022/11/7 9:53
 *
 * @author DingJiaxiong
 */

@LocalTCC
public interface AccountTCCService {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                @BusinessActionContextParameter(paramName = "money") int money);

    boolean confirm(BusinessActionContext ctx);

    boolean cancel(BusinessActionContext ctx);

}

OK,这样T、C、C 就有了

创建新的 “冻结表 ”

老师已经给了资料

在这里插入图片描述

将其导入到微服务使用的 数据库 seata-demo 中

在这里插入图片描述

OK

其实两个实体类,虎哥 都写好了

账户表

在这里插入图片描述

冻结表

在这里插入图片描述

mapper 也写好了【两个】

冻结表的数据层接口

在这里插入图片描述

账户表的数据层接口

在这里插入图片描述

OK,实现TCC 的业务层接口【就我们最开始写那个】

package cn.itcast.account.service.impl;

import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountTCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * ClassName: AccountTCCServiceImpl
 * date: 2022/11/7 10:03
 *
 * @author DingJiaxiong
 */

@Slf4j
@Service
public class AccountTCCServiceImpl implements AccountTCCService {

    //接口注入
    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountFreezeMapper freezeMapper;

    //try方法【资源检测】
    @Override
    @Transactional
    public void deduct(String userId, int money) {

        //0. 获取事务id
        String xid = RootContext.getXID();

        //1. 判断freeze 中是否有冻结记录,如果有,则一定是cancel 执行过,需要拒绝业务
        AccountFreeze oldFreeze = freezeMapper.selectById(xid);
        if (oldFreeze != null){

            //cancel 执行过,需要拒绝业务
            return;
        }

        //1. 扣减可用余额
        accountMapper.deduct(userId,money);
        //2. 记录冻结金额、事务状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);

        freezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {

        //1. 获取事务id
        String xid = ctx.getXid();

        //2. 根据id删除冻结记录
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {

        //0. 查询冻结记录
        String xid = ctx.getXid();
        String userId = ctx.getActionContext("userId").toString();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        //1. 空回滚的判断,判断freeze 是否为null,为null证明try 没执行,需要空回滚
        if (freeze == null) {
            //证明try 没执行,需要空回滚
            freeze = new AccountFreeze();
            freeze.setUserId(userId);
            freeze.setFreezeMoney(0);
            freeze.setState(AccountFreeze.State.CANCEL);
            freeze.setXid(xid);

            freezeMapper.insert(freeze);
            return true;
        }

        //2. 幂等判断
        if (freeze.getState() == AccountFreeze.State.CANCEL){
            // 已经处理过一次cancel 了,无需重复处理
            return true;
        }

        //1. 恢复可用余额
        accountMapper.refund(freeze.getUserId(),freeze.getFreezeMoney());

        //2. 将冻结金额清零、状态改为cancel
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        //更新
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }
}

我超,真的费程序员

修改一下控制器

在这里插入图片描述

OK,重启服务开始测试

在这里插入图片描述

先记录一下数据库现在的状态

在这里插入图片描述

当前账户余额 是 400

在这里插入图片描述

冻结表也是空的

在这里插入图片描述

订单当前也是两条

在这里插入图片描述

库存为 6

先来个正确的测试

在这里插入图片描述

直接send

在这里插入图片描述

哇靠,挂掉了

看看日志

在这里插入图片描述

不能连接到8091 ,seata 服务挂了?

在这里插入图片描述

重启一下seata 服务,和三个微服务

在这里插入图片描述

在这里插入图片描述

再试一次

在这里插入图片描述

OK,成功 了,返回 了订单id

再次查看数据库

在这里插入图片描述

新增了一条订单

在这里插入图片描述

余额减少了 200

在这里插入图片描述

库存余额 也减少 了2

在这里插入图片描述

freeze 依然是空的,因为confirm 后会删除记录

现在来一次异常情况

在这里插入图片描述

直接send

在这里插入图片描述

OK,再次查看数据库【预期会回滚】

在这里插入图片描述

订单依然是3 个

在这里插入图片描述

账户余额 没有变化

在这里插入图片描述

库存也没有减少

在这里插入图片描述

OK,冻结表有东西了

IDEA 控制台

在这里插入图片描述

这就是TCC 模式的实现

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

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

相关文章

第34篇 网络(四)FTP(二)

导语 前面讲述了一个最简单的FTP客户端程序的编写,这一节我们将这个程序进行扩展,使其可以浏览并能下载服务器上的所有文件。 环境:Windows Xp Qt 4.8.5QtCreator 2.8.0 目录 一、修改界面二、功能实现 正文 一、修改界面 我们删除了T…

当vivo领先后,该学着“快”起来了

文|智能相对论 作者|佘凯文 随着一个个大热球队的爆冷,今年世界杯赛事正在渐入高潮。就目前的形势来看,世界杯最大的悬念在于究竟是“老王”圆梦,还是“新王”登基,又或者是摩洛哥这只黑马一黑到底。 新老球星的更迭&#xff0…

Selenium浏览器自动化测试框架

selenium简介 介绍 Selenium [1] 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google C…

设计模式概述(一)

很多小伙伴,不知道设计模式是什么? 通常我们所说的设计模式是一种设计方案,是前人留下的经验及最佳实践。 想要学习设计模式,至少要把面向对象的基本结构全部了解。 设计模式,是建立在一定基础上的思维训练。 学习设…

macos12.6安装配置opencv4.6.0+opencv contrib4.6.0

1.系统准备好,安装依赖python版本高一点的,并且安装上numpy。 brew install cmake gui及cmake,可能装cmake gui的时候有点问题,先装gui再装cmake。 2.提前下载源码,Releases - OpenCV要求opencv与opencv contrib版本一…

Metal每日分享,UV去雾滤镜效果

本案例的目的是理解如何用Metal实现去雾效果滤镜,类似于UV过滤器; Demo HarbethDemo地址 实操代码 // 去雾效果滤镜 let filter C7Haze.init(distance: 0.5, slope: 0.5)// 方案1: ImageView.image try? BoxxIO(element: originImage, filters: [f…

MyBatis ---- MyBatis的逆向工程

MyBatis ---- MyBatis的逆向工程1. 创建逆向工程的步骤a>添加依赖和插件b>创建MyBatis的核心配置文件c>创建逆向工程的配置文件d>执行MBG插件的generate目标2. QBC查询正向工程:先创建 Java 实体类,由框架负责根据实体类生成数据库表。Hiber…

Spring源码深度解析:十五、@Aspect方式的AOP中篇 - getAdvicesAndAdvisorsForBean

一、前言 文章目录:Spring源码深度解析:文章目录 在上篇中我们概述了Aop 实现的逻辑,但是由于篇幅原因,我们将一部分内容拆成了中篇和下篇内容。本篇即中篇,内容主要是讲述 在 Bean创建过程中Aop 挑选适用于当前Bean…

尚医通-MyBatistPlus:修改和自动填充-乐观锁(三)

目录: (1)MyBatistPlus:修改和自动填充 (2)MyBatis-Plus-乐观锁 (1)MyBatistPlus:修改和自动填充 1、更新操作 注意:update时生成的sql自动是动态sql&…

14 - 局部段描述符表

---- 整理自狄泰软件唐佐林老师课程 文章目录1. 什么是局部段描述符表(LDT)1.1 局部段描述符选择子1.2 局部段描述符表LDT1.3 问题1.4 LDT的定义和使用2. 编程实验:使用LDT实现新功能3. 多任务程序设计的实现思路4. 待解决的问题:…

第51篇 Qt 5.5全新的开始

导语 时间转眼而逝,看一下上次发的教程,已经是一年前的事情了。这一年发生了很多事情,包括自己也包括Qt。当然,自己很忙或者说为了编写《Qt 5编程入门》这些理由,并不能为一年的搁置进行开脱,所以这里首先…

人工智能前沿——6款AI绘画生成工具

>>>深度学习Tricks&#xff0c;第一时间送达<<< 目录 一、【前言】 二、【6款AI绘画生成工具】 1.DeepAI 2.NightCafe 3.Deep Dream Generator 4.StarryAI 5.Fotor 6.Pixso 一、【前言】 AI不仅影响商业和医疗保健等行业&#xff0c;还在创意产业中…

Flutter Web CORS解决方案2-代理转发协议

Flutter Web CORS解决方案2local-cors-proxyshelf_proxydart run shelf_proxyflutter run --dart-definewrap with shellhelp & usagemode & confrun & debuglaunch with proxyvscodeAndroid Studio遗留问题本文介绍第二种解决FlutterWeb CORS问题的方案&#xff1…

[附源码]Nodejs计算机毕业设计基于web的企业人事管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Centos7下Samba服务器配置

环境 vm下centos7.6&#xff0c;IP地址&#xff1a;192.168.139.200 Samba概述 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件&#xff0c;由服务器及客户端程序构成。SMB&#xff08;Server Messages Block&#xff0c;信息服务块&#xff09;是一种在局域网上共享文…

STM32H747AGI6技术、STM32H747AII6规格、STM32H747BGT6产品概述

产品概述&#xff1a;STM32H7高性能MCU基于高性能Arm Cortex-M7 32位RISC内核&#xff0c;工作频率高达400MHz。Cortex-M7内核具有浮点单元 (FPU) 精度&#xff0c;支持Arm双精度&#xff08;符合IEEE 754标准&#xff09;和单精度数据处理指令与数据类型。STM32H7 MCU支持全套…

第48篇 进阶(八) 3D绘图简介

导语 OpenGL是一个跨平台的用来渲染3D图形的标准API。在Qt中提供了QtOpenGL模块&#xff0c;从而很轻松地实现了在Qt应用程序中使用OpenGL&#xff0c;这主要是在QGLWidget类中完成的。因为3D绘图涉及到了专业方面的内容&#xff0c;我们下面只是讲解最简单的使用&#xff0c;…

Java基础之LinkedList

Java基础之LinkedList一、介绍二、add()一、介绍 底层是一个双向链表实现的List&#xff0c;内部每一个节点采用内部类Node表示&#xff0c;通过first、last引用分别指向链表的第一和最后一个元素非线程安全&#xff0c;可以用Collections.synchronizedList()方法对其进行包装…

Android入门第44天-Android里使用动态BroadCast

BroadCast是什么 BroadcastReceiver就是应用程序间的全局大喇叭&#xff0c;即通信的一个手段&#xff0c; 系统自己在很多时候都会发送广播&#xff0c;比如电量低或者充足&#xff0c;刚启动完&#xff0c;插入耳机&#xff0c;你有一条新的微信消息。。。这种都是使用Broad…

Windows实时运动控制软核(二):LOCAL高速接口测试之Qt

今天&#xff0c;正运动小助手给大家分享一下MotionRT7的安装和使用&#xff0c;以及使用Qt对MotionRT7开发的前期准备。 01 MotionRT7简介 MotionRT7是深圳市正运动技术推出的跨平台运动控制实时内核&#xff0c;也是国内首家完全自主自研&#xff0c; 自主可控的Windows运动…