【bug】重复请求的幂等问题

news/2024/12/16 17:18:23/文章来源:https://www.cnblogs.com/little-nobody/p/18610672

问题背景

某验收系统,客户发起验收流程时,由于前端没有做防重点击的限制,导致申请按钮连续点击了多次,重复发起了多条流程

历史逻辑

后端为了保证接口幂等,在发起验收流程的代码中加了几层逻辑如下:

  1. 判断验收记录状态是否为待发起, 如果不是,则立刻返回失败
  2. 发起流程的入口加了一层用户维度的锁,可以保证同一用户无法同时进入流程处理逻辑,伪代码如下:
@Component
public class ProcessManager {private final CopyOnWriteArraySet<String> userLock = new CopyOnWriteArraySet<>();/*** 流程操作*/public void doAction(入参) {// 拦截器会提前解析token并将用户信息存入上下文AuthUser currentUser = ContextUtil.getCurrentUser();try {// 这里将上下文中的用户id存入CopyOnWriteArraySet中,如果保存失败说明当前用户正在操作流程,返回失败if (!userLock.add(currentUser.getId())) {throw new BusinessException("正在处理中,请勿重复操作");}// 此处是流程处理代码入口...} finally {// 流程代码结束后释放锁,放在finally代码块中,防止死锁
            userLock.remove(currentUser.getId());// 此处清理流程上下文信息...
        }}}
  1. 流程处理完后,更新数据库中的验收记录状态为已发起

以上逻辑梳理成总体的伪代码如下:

@Autowired
privarte ProcessManager processManager;public void startApply(入参) {// 校验验收记录的状态Record record = getRecord(入参);if (!record.getStatus().equals(待发起)) {返回失败}前置业务流程...// 发起流程
    processManager.doAction(入参);// 更新状态
    record.setStatus(待审批);baseMapper.updateById(record);
}

 

 可以转化为如下的流程图

 

问题分析

当出现以下情况时,会出现重复发起的问题

首先,为了保证事务的原子性,整个方法是一个大事务

多个线程同时查询验收记录,会查询到同样的未被改变状态的数据,会同时通过状态校验,进入到以下的情况:

 

由于代码执行有快慢,线程1率先发起了流程,并且完成了

 

此时线程2还未尝试获取锁,线程1就已经释放了锁,这时线程2也能顺利进入发起流程的代码,再次发起流程

 

当线程1和线程2都执行完成后,数据库中就生成了两条流程,出现了幂等性问题

解决思路

数据库锁

 

最开始查询验收记录时,可以在SQL后增加“for update”,将该条记录锁住,并且for update是当前读,能够读取到最新的已提交的数据

优点:可以保证只有一个线程进入后续代码

缺点:排它锁太重了,其他线程需要等待事务结束才能获取到锁查询数据,会严重影响性能

分布式锁

 

优点:可以保证只有一个线程进入后续代码,性能好,不影响其他查询

缺点:引入redis分布式锁又会面临redis集群的其他问题,可能会死锁或锁失效

数据库唯一索引

在流程实例表增加唯一索引,唯一字段根据业务属性决定,创建流程实例时把insert语句的方法用try-catch包裹起来,检测DuplicateKeyException异常,如果发生了重复键冲突,则直接报错

 

优点:根本上确保了流程实例的唯一性

缺点:每个线程都会执行到前置的业务处理,这部分是多余的计算

结论

通过对比优缺点,最终选择了数据库唯一索引的办法解决问题

首先根据业务特征,在流程实例表b_approve_instance增加了对应唯一索引

之后在insert的方法外包裹一层try-catch,代码如下

try {baseMapper.insert(instance);
} catch (DuplicateKeyException e) {throw new BusinessException("已提交,请勿重复提交");
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Deformable DETR

PDF:https://arxiv.org/pdf/2010.04159 Code:https://github.com/fundamentalvision/Deformable-DETR 一、大体内容 前面介绍DETR时,说明了其还存在对小物体检测效果不佳和训练慢的问题,Deformable DETR引入了DCN(Deformable Convolutional Networks)并将其和DETR相结合,借…

【蓝队】HW中盛行的Java内存马,如何全面检测?

一、背景 1.1 Java内存马是什么? 内存马是一种仅在内存中运行、没有文件落地的恶意程序,因此具有较强的隐蔽性,能够避开常规的基于文件系统的检测。Java内存马是针对Java语言的内存马,它利用Java语言的动态特性,如类加载机制、动态代理和反射技术等,在Java应用的内存中注…

Express的使用笔记9 使用bcrypt算法给用户密码加密

先了解一下bcrypt算法,一种基于Blowfish密码学算法的密码散列函数,用于在密码存储时抵抗暴力破解攻击,通过在散列过程中加salt来提高安全性,salt是个随机生成的数据串,与密码一起被散列,使得即使两个相同的密码也会产生不同的散列值。bcrypt算法允许开发者指定工作因子(…

4.mysql中的存储过程

创建存储过程和函数 CREATE[DEFINER = {USER | CURRENT_USER}] # 定义者是谁PROCEDURE sp_name ([proc_parameter[,...]])[characteristic ...] routine_bodyCREATE [DEFINER = {USER | CURRENT_USER}]FUNCTION sp_name ([function_name[,...]])[characteristic ...] routine_…

印象笔记使用

vscode安装插件登录印象笔记,开通token点击插件页面的设置填写url和tokenctrl + shift + pever new - 新建笔记 ever open - 打开笔记 ever search - 搜索笔记 ever publish - 发布笔记 ever sync - 同步笔记新建笔记下载安装windows客户端,功能比网页端更全面客户端才能导出…

(BIBM-2024) 用于药物相互作用预测的可解释多视图注意网络

用于药物相互作用预测的可解释多视图注意网络 论文标题: Interpretable multi-view attention network for drug-drug interaction prediction 论文地址: https://ieeexplore.ieee.org/document/10385757 论文期刊: BIBM 2024 摘要 药物间相互作用(DDI)在药物发现中发挥着越来…

Volatility取证工具安装教程

linux安装vol2.6 1.准备工作 准备一台虚拟机,拥有python2版本(虚拟机以kali为例) 准备Volatility2.6安装包 volatilityfoundation/volatility: An advanced memory forensics framework 准备反编译库安装包 vext01/distorm3: distorm3 2.安装步骤详解(全程在root用户下操作…

[React]AntDesign 4.x 汉化

antd汉化,适用于4.x转载自:https://blog.csdn.net/weixin_43013802/article/details/132870349全局汉化,在main.ts中引入下面代码:import{ ConfigProvider }fromantd import locale from antd/locale/zh_CN; import dayjs/locale/zh-cn;ReactDOM.createRoot(document.getEl…

线性回归(linear regression)

其实线性回归不过就是在做两件事,画一条线并判断这条线到各个点的距离。 如下图:其中这条线便是距离各个点距离总和最小的直线。也就是e+u+w+b+a总和在直线为这个情况下最小。但是什么时候这条线是我们需要的线呢?-- 线到各个点最短的时候便是。 我们先理解一下什么是凹函数…

数据库安全性与权限管理

title: 数据库安全性与权限管理 date: 2024/12/16 updated: 2024/12/16 author: cmdragon excerpt: 数据库安全性与权限管理是保护数据不被未授权访问和操控的关键所在。通过实施有效的安全措施和细粒度的权限控制,可以确保数据库的完整性、机密性和可用性。 categories:前端…

数据整合+团队协作,电商选品效率提升100%!

选品快准狠!在线协同助力电商团队做出更聪明的决策 在电商行业,“选品”决定成败。无论是发现爆款、避开雷区,还是追踪最新趋势,每一个决策都离不开团队协作与信息整合。然而,大量的电商团队仍旧面临以下常见问题: - 决策过程拉长,错失销售机会。 - 数据不统一,选品思路…

xshell类似的工具,还有哪些Xshell类似的工具呢

Xshell是一款功能强大的远程连接工具,广泛用于SSH、Telnet和Rlogin协议,帮助用户轻松连接和管理远程服务器。然而,Xshell并不是唯一的远程连接工具,市面上还有其他一些类似的工具,能够提供类似甚至更丰富的功能。那么,除了Xshell,还有哪些类似的远程连接工具呢?以下将为…