使用状态机实现幂等性

news2024/11/15 8:02:59

文章目录

  • 背景
  • 幂等概念
  • 适用场景
  • 示例代码
  • 上述代码状态流转

背景

        在某些场景下,可以使用状态机来实现幂等性。将业务流程抽象为一个状态机,定义各个状态之间的转换规则。当收到一个请求时,根据当前状态和请求类型来判断是否允许执行操作,如果允许则执行操作并更新状态,否则拒绝操作。这样可以确保每个操作在合适的状态下执行,避免重复操作导致的问题。

幂等概念

        幂等(Idempotency)是指对于一个系统,一个具有幂等性质的操作,无论执行多少次,其结果始终保持一致。在分布式系统和网络编程中,幂等性是一种非常重要的概念。确保接口幂等性可以避免重复操作导致的数据不一致和其他潜在问题。

        在计算机科学中,幂等性通常用于描述一种能够忽略重复调用的操作。例如,对于一个删除记录的操作,如果删除成功,无论执行多少次,记录都会保持被删除的状态。类似地,对于一个更新操作,如果更新成功,无论执行多少次,更新后的状态都保持不变。

适用场景

  1. 确定状态:根据业务场景,确定系统需要的状态。例如,在订单处理中,可能需要如下状态:待支付、已支付、已发货、已收货、已取消等。
  2. 定义状态转换规则:针对每个状态,定义允许的操作以及操作后的新状态。例如,在待支付状态下,允许操作是支付,支付成功后状态转为已支付。
  3. 操作条件判断:在执行操作之前,根据当前状态和请求类型判断是否允许执行操作。如果允许,则执行操作并更新状态;否则拒绝操作。
  4. 存储状态:将状态持久化存储,例如存储在数据库中。这样,在处理请求时,可以获取当前状态,并根据状态执行相应的操作。
  5. 幂等性处理:当接收到重复的请求时,可以根据当前状态判断请求是否有效。如果当前状态不允许执行请求的操作,则直接返回之前的响应结果,实现幂等性。

示例代码

        在这个示例中,创建了一个基于有限状态机的订单处理系统。我们首先定义了状态和操作的枚举类型,然后定义了一个状态转换接口。接着,我们创建了一个表示订单的类,并在主方法中初始化一个待支付的订单。

        接下来,我们创建了一个状态机映射,用于存储状态转换规则。对于每个状态和操作,我们定义了一个状态转换接口的实现。在执行操作时,我们根据订单的当前状态和请求的操作来查找相应的状态转换。如果找到了合适的状态转换,就执行转换并更新订单状态。如果没有找到合适的状态转换,说明操作无效。

import java.util.HashMap;
import java.util.Map;

public class StateMachineExample {

    // 定义状态枚举
    public enum State {
        PENDING_PAYMENT,
        PAID,
        CANCELED
    }

    // 定义操作枚举
    public enum Operation {
        PAY,
        CANCEL
    }

    // 定义状态转换接口
    public interface StateTransition {
        State execute();
    }

    // 定义订单类
    public static class Order {
        private State state;

        public Order(State state) {
            this.state = state;
        }

        public State getState() {
            return state;
        }

        public void setState(State state) {
            this.state = state;
        }
    }

    public static void main(String[] args) {
        // 创建一个待支付的订单
        Order order = new Order(State.PENDING_PAYMENT);

        // 创建状态机映射
        Map<State, Map<Operation, StateTransition>> stateMachine = new HashMap<>();

        // *************定义状态转换规则*************//
        stateMachine.put(State.PENDING_PAYMENT, new HashMap<>());
        //待支付状态下业务规则
        stateMachine.get(State.PENDING_PAYMENT).put(Operation.PAY, () -> {
            System.out.println("支付成功");
            return State.PAID;
        });
        stateMachine.get(State.PENDING_PAYMENT).put(Operation.CANCEL, () -> {
            System.out.println("订单已取消");
            return State.CANCELED;
        });

        //支付状态下业务规则
        stateMachine.put(State.PAID, new HashMap<>());
        stateMachine.get(State.PAID).put(Operation.PAY, () -> {
            System.out.println("重复支付,忽略");
            return State.PAID;
        });

        //订单取消状态下业务规则
        stateMachine.put(State.CANCELED, new HashMap<>());
        stateMachine.get(State.CANCELED).put(Operation.PAY, () -> {
            System.out.println("订单已取消,无法支付");
            return State.CANCELED;
        });
        // *****************************************//
        
        

        // 执行操作
        executeOperation(order, stateMachine, Operation.PAY);
        executeOperation(order, stateMachine, Operation.PAY);
        executeOperation(order, stateMachine, Operation.CANCEL);
    }

    // 根据当前状态和操作执行状态转换
    private static void executeOperation(Order order, Map<State, Map<Operation, StateTransition>> stateMachine, Operation operation) {
        State currentState = order.getState();
        StateTransition transition = stateMachine.get(currentState).get(operation);

        if (transition != null) {
            State newState = transition.execute();
            order.setState(newState);
        } else {
            System.out.println("操作无效");
        }
    }
}

执行结果
在这里插入图片描述

上述代码状态流转

  1. 当订单处于 PENDING_PAYMENT(待支付)状态时,执行 PAY 操作会将订单状态变为 PAID(已支付);执行 CANCEL 操作会将订单状态变为 CANCELED(已取消)。
  2. 当订单处于 PAID(已支付)状态时,再次执行 PAY 操作会被忽略,订单状态保持为 PAID
  3. 当订单处于 CANCELED(已取消)状态时,不存在定义的状态转换。

这样就保证在多次操作的时候只有一个结果,就保证了幂等性
在这里插入图片描述

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

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

相关文章

MySQL高级篇——存储引擎和索引

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线牛客面试题_java黑马笔记 目录 一、存储引擎 1.1、查看、设置存储引擎的命令 1.2、InnoDB引擎 1.2.1、特点 1.2.2、优势 1.2.3、InnoDB事务的ACID特…

[读书笔记] 从问题和公式角度理解 Diffusion Model

[小全读书笔记] 从问题和公式角度理解 Diffusion Model 1. Diffusion Model的结构1.1 定义与限制1.2 定义与限制的数学体现 2. Diffusion Model的模型训练2.1 似然函数转换成ELBO2.2 拆解ELBO2.3 求解关键&#xff1a; q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt−1…

垃圾回收概述

什么是垃圾 垃圾收集&#xff0c;不是Java语言的伴生产物。早在1960年&#xff0c;第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。 关于垃圾收集有三个经典问题&#xff1a; 哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&#xff1f; 垃圾收…

在线审片工具是什么,安捷秀如何在线审片?

当影视内容完成拍摄后&#xff0c;即进入漫长、繁复的后期制作过程&#xff0c;审片就是后期制作过程中一个非常重要的环节。传统的审片需要专门的场地、音画设备&#xff0c;召集人员在特定时间进行&#xff0c;人财物的成本都非常高&#xff0c;在此情况下&#xff0c;在线审…

GeoServer使用MySQL数据库出现“Error decoding wkb”错误的一种情况

错误 请看一下GeoServer官方文档的警告 Warning:Currently the MySQL extension is unmaintained and carries unsupported status. While still usable, do not expect the same reliability as with other extensions. 没事不要特立独行使用MySQL当GeoServer的空间数据库&am…

文件和用户管理

Linux基础 提示&#xff1a;个人学习总结&#xff0c;仅供参考。 一、Linux系统部署 二、服务器初始化 三、文件和用户管理 提示&#xff1a;文档陆续更新整理 文件和用户管理 Linux基础一、Linux目录结构二、文件管理1.文件类型2.文件管理命令 三、用户管理1. 用户/组基本概…

MySQL隐式类型转换

当运算符与不同类型的操作数一起使用时&#xff0c;会发生类型转换以使操作数兼容。有些转换是隐式发生的。例如&#xff0c;MySQL会根据需要自动将字符串转换为数字&#xff0c;反之亦然。 转换规则 如果一个或两个参数都为NULL&#xff0c;则比较结果为NULL 。但是相等比较…

Android Wifi 扫描

今天拿了个新需求&#xff0c;要求为工厂开发一个扫地机模组检测功能的App&#xff0c;需求逻辑&#xff1a; 1.可以选择机器支持的WBR3 模组和WR3 模组&#xff1b; 2.可以选择机器热点名称的前缀&#xff1a;Thamtu 和 SmartLife&#xff0c;还有自定义输入前缀&#xff1b…

Java概述

Java语言简史&#xff1a; 是SUN(Stanford University Network&#xff0c;斯坦福大学网络公司 ) 1995年推出的一门高级编程语言。 是一种面向Internet的编程语言。Java一开始富有吸引力是因为Java程序可以在Web浏览器中运行。这些Java程序被称为Java小程序&#xff08;applet&…

foldersync使用感受

foldersync简介 ​ FolderSync pro是一款功能非常强大的设备本地存储(包括SD卡)文件/文件夹与云存储同步应用。它可以将手机中的文件自动同步到云端空间&#xff0c;支持包括 FTP、WebDAV、Dropbox、 Google Docs 在内的众多空间。 FolderSync Pro 支持各种不同的云服务商和文件…

CTA策略趋势类

趋势策略 趋势策略日内策略Hilbert 策略R-Braker 策略Dual Thrust 策略菲阿里四价策略空中花园策略 日间策略移动平均线MACD 策略Aberration 策略ATR 策略动量策略肯特纳通道自动识别趋势的追涨交易策略 趋势策略 市场只有两种状态&#xff1a;震荡和单边。 而两种市场状态只…

springboot项目:瑞吉外卖 前后端详细分析 part4

part 1 part 2 part 3 part 4 本页 文章目录 5 套餐管理5.1 新增套餐5.1.1 整体分析5.1.2 前端分析5.1.3 后端分析 持续更新中 5 套餐管理 5.1 新增套餐 5.2 套餐信息分页查询 5.3 删除套餐 其他小功能都比较简单且类似&#xff0c;不再赘述 5.1 新增套餐 5.1.1 整体分析 套…

jmeter取样器javaRequest脚本8

1,创建一个maven工程2,通过maven编译打包生成一个jar包3,重启jmeter&#xff0c;新建java request请求4,开始执行脚本本文永久更新地址: 1,创建一个maven工程 在pom.xml文件中添加 maven下载地址&#xff1a;https://mvnrepository.com/artifact/org.apache.jmeter/ApacheJMe…

【MySQL】关于 SQL 语句执行分析的二三事

一、为什么要发生这件事 确实&#xff0c; 平时我们增删改查写的好好的&#xff0c; 各种业务代码&#xff0c;各种小接口写的不亦乐乎&#xff0c;正常是没时间干这个的&#xff0c;但是但是&#xff0c;这不是还有点技术追求嘛&#xff0c;假如我们平时测一个小接口&#xf…

【LeetCode】199.二叉树的右视图

1.问题 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,4] 示例 2: 输入: [1,null,3] 输出: [1,3] 示例 3: 输入: [] 输出: []…

类加载过程

基本说明 反射机制是Java实现动态语言的关键&#xff0c;也就是通过反射实现类动态加载。 静态加载&#xff1a;编译时加载相关的类&#xff0c;如果没有则报错&#xff0c;依赖性太强动态加载&#xff1a;运行时加载需要的类&#xff0c;如果运行时不用该类&#xff0c;即使…

C++关于线程的一些操作

线程创建和接收 std::this_thread::get_id()获取当前线程的线程ID std::this_thread::yield()让步结束当前线程的时间片 int main() {vector<thread> threads(2);threads[0] thread([]() {cout << this_thread::get_id() << endl;});threads[1] thread([](…

Baumer工业相机中偏振相机如何使用Baumer堡盟GAPI SDK来进行偏振数据的计算转换输出(C#)

项目场景 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能&#xff0c;可以实时传输高分辨率图像。此外&#xff0c;该相机还具…

ansible自动运维——ansible使用临时命令通过模块来执行任务

大家好&#xff0c;这里是天亮之前ict&#xff0c;本人网络工程大三在读小学生&#xff0c;拥有锐捷的ie和红帽的ce认证。每天更新一个linux进阶的小知识&#xff0c;希望能提高自己的技术的同时&#xff0c;也可以帮助到大家 另外其它专栏请关注&#xff1a; 锐捷数通实验&…

【机器学习实战】Python基于SVD奇异值分解进行矩阵分解(八)

文章目录 1 前言1.1 奇异值分解1.2 奇异值分解的应用 2 简单计算SVD2.1 NumPy 计算 SVD2.2 scikit-learn 计算截断 SVD2.3 scikit-learn 计算随机 SVD 3 demo数据演示3.1 导入函数3.2 导入数据3.3 计算SVD 4 讨论 1 前言 1.1 奇异值分解 奇异值分解&#xff08;Singular Valu…