支付幂等性的实现中,通过“一锁、二判、三更新”

在这个支付幂等性的实现中,通过“一锁、二判、三更新”严格控制了支付链接生成接口的幂等性,确保同一业务单号在同一时间只会生成一个有效的支付链接,避免重复支付或其他意外操作。
在这里插入图片描述

@Facade
@DistributeLock(keyExpression = "#payCreateRequest.bizNo", scene = "GENERATE_PAY_URL")
public PayCreateResponse generatePayUrl(PayCreateRequest payCreateRequest) {
    PayCreateResponse response = new PayCreateResponse();
    PayOrder payOrder = payOrderService.create(payCreateRequest);

    if (payOrder.getOrderState() != PayOrderState.TO_PAY) {
        response.setPayOrderId(payOrder.getPayOrderId());
        response.setPayUrl(payOrder.getPayUrl());
        response.setSuccess(true);
        return response;
    }

    PayChannelResponse payChannelResponse = doPay(payCreateRequest, payOrder);

    if (payChannelResponse.getSuccess()) {
        boolean updateResult = payOrderService.paying(payOrder.getPayOrderId(), payChannelResponse.getPayUrl());
        Assert.isTrue(updateResult, () -> new BizException(RepoErrorCode.UPDATE_FAILED));
        response.setSuccess(true);
        response.setPayOrderId(payOrder.getPayOrderId());
        response.setPayUrl(payChannelResponse.getPayUrl());
    } else {
        response.setSuccess(false);
        response.setResponseCode(payChannelResponse.getResponseCode());
        response.setResponseMessage(payChannelResponse.getResponseMessage());
    }

    return response;
}

@Service
public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
    private static final Logger logger = LoggerFactory.getLogger(PayOrderService.class);

    @Autowired
    private PayOrderMapper payOrderMapper;

    public PayOrder create(PayCreateRequest payCreateRequest) {
        PayOrder existPayOrder = payOrderMapper.selectByBizNoAndPayer(
            payCreateRequest.getPayerId(),
            payCreateRequest.getBizNo(),
            payCreateRequest.getBizType().name(),
            payCreateRequest.getPayChannel().name()
        );

        if (existPayOrder != null) {
            if (existPayOrder.getOrderState() != PayOrderState.EXPIRED) {
                return existPayOrder;
            }
        }

        PayOrder payOrder = PayOrder.create(payCreateRequest);
        boolean saveResult = save(payOrder);
        Assert.isTrue(saveResult, () -> new BizException(RepoErrorCode.INSERT_FAILED));

        return payOrder;
    }
}

1. 一锁

在方法入口处使用了自定义注解 @DistributeLock,并将锁的内容设置为业务单号 bizNo。该锁是一个互斥锁,可以是分布式锁(如Redis锁)或数据库悲观锁。其作用是确保在同一时刻,同一个业务单号的请求只会有一个线程可以进行操作,其他请求会被阻塞,直到锁释放。这一步确保了多线程环境下的操作安全,防止多个请求同时生成支付链接。

2. 二判

PayOrderService.create 方法中实现了幂等性判断。首先,通过业务单号、付款方、支付类型和支付渠道查询数据库,检查是否已有相同条件的支付单存在。如果存在,且状态不为过期(如已支付、处理中等),则直接返回已有的支付单信息,包括支付链接等内容,不会重复生成新的支付单。这一判断基于数据库查询,可以通过唯一性索引、流水表或状态机来提高查询效率,防止重复操作。

3. 三更新

如果第二步判断不存在在途支付单,则创建一个新的支付单,并调用支付渠道生成支付链接。生成的支付链接会更新到支付单中,并将该支付单持久化到数据库。这一更新操作包括将生成的支付链接更新到数据库,同时返回给前端。这一步确保了新的支付单被正确保存,链接准确更新,从而完成一次新的支付操作。

总结

该方法通过“一锁、二判、三更新”三步流程有效实现了支付接口的幂等性控制:

  • 加锁确保了同一业务单号在并发情况下的唯一性操作。
  • 幂等性判断避免了重复生成支付单。
  • 数据更新确保了新生成的支付链接能正确返回并持久化。

这种设计有效地防止了重复支付操作,并确保了系统的可靠性和数据的一致性。

支付幂等性是指在支付系统中,无论同一个支付请求被重复调用多少次,结果都应该是相同的,并且不会导致重复支付或数据不一致的问题。即在网络请求可能被多次触发的情况下,确保同一笔支付请求仅会成功一次,不会因为系统的重试或用户的重复点击而多次扣款或生成多个支付订单。

为什么支付幂等性很重要?

在支付场景中,由于网络波动、请求超时等原因,客户端或服务端可能会多次发送同一个支付请求。如果支付系统没有做幂等性处理,可能会出现以下问题:

  • 多次扣款:用户因同一个请求被多次扣款,导致资金损失。
  • 数据不一致:生成多个支付订单,导致订单状态、库存等数据混乱。
  • 用户体验差:用户可能因重复支付或状态异常而产生疑惑,甚至失去信任。

如何实现支付幂等性?

实现支付幂等性通常包含以下几种方法:

  1. 唯一性标识:为每个支付请求生成一个唯一的业务单号(如订单号),并在每次支付请求中携带该标识。服务器可以根据该标识检查该支付是否已经处理过,避免重复处理。

  2. 幂等性锁:在支付操作前对订单加锁(如分布式锁或悲观锁),确保同一时间只有一个请求能成功执行,防止并发请求导致重复扣款。

  3. 状态检查:在执行支付操作前检查订单状态,如果订单已经支付成功或处于支付处理中,则直接返回支付结果,避免重复支付。

  4. 数据库唯一索引:通过数据库的唯一索引约束(如订单号)来防止重复插入支付订单。

总结

支付幂等性是支付系统中一个非常重要的特性,它通过一系列控制措施,确保同一支付请求即使被重复调用,也不会产生多次扣款、重复订单等问题,保障用户资金安全和数据一致性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Charles抓包_Android

1.下载地址 2.破解方法 3.安卓调试办法 查看官方文档&#xff0c;Android N之后抓包要声明App可用User目录下的CA证书 3.1.在Proxy下进行以下设置&#xff08;路径Proxy->Proxy Settings&#xff09; 3.1.1.不抓包Windows&#xff0c;即不勾选此项&#xff0c;免得打输出不…

Chromium Mojo(IPC)进程通信演示 c++(3)

122版本自带的mojom通信例子channel-associated-interface 仅供学习参考&#xff1a; codelabs\mojo_examples\03-channel-associated-interface-freezing 其余定义参考上一篇文章&#xff1a; Chromium Mojo(IPC)进程通信演示 c&#xff08;2&#xff09;-CSDN博客​​​​…

鸢尾博客项目开源

1.博客介绍 鸢尾博客是一个基于Spring BootVue3 TypeScript ViteJavaFx的客户端和服务器端的博客系统。项目采用前端与后端分离&#xff0c;支持移动端自适应&#xff0c;配有完备的前台和后台管理功能。后端使用Sa-Token进行权限管理,支持动态菜单权限&#xff0c;服务健康…

【模型学习之路】手写+分析bert

手写分析bert 目录 前言 架构 embeddings Bertmodel 预训练任务 MLM NSP Bert 后话 netron可视化 code2flow可视化 fine tuning 前言 Attention is all you need! 读本文前&#xff0c;建议至少看懂【模型学习之路】手写分析Transformer-CSDN博客。 毕竟Bert是tr…

word及Excel常见功能使用

最近一直在整理需规文档及表格&#xff0c;Word及Excel需要熟练使用。 Word文档 清除复制过来的样式 当复制文字时&#xff0c;一般会带着字体样式&#xff0c;此时可选中该文字 并使用 ctrlshiftN 快捷键进行清除。 批注 插入->批注&#xff0c;选中文本 点击“批注”…

【C++篇】数据之林:解读二叉搜索树的优雅结构与运算哲学

文章目录 二叉搜索树详解&#xff1a;基础与基本操作前言第一章&#xff1a;二叉搜索树的概念1.1 二叉搜索树的定义1.1.1 为什么使用二叉搜索树&#xff1f; 第二章&#xff1a;二叉搜索树的性能分析2.1 最佳与最差情况2.1.1 最佳情况2.1.2 最差情况 2.2 平衡树的优势 第三章&a…

【Mac】安装 VMware Fusion Pro

VMware Fusion Pro 软件已经正式免费提供给个人用户使用&#xff01; 1、下载 【官网】 下拉找到 VMware Fusion Pro Download 登陆账号 如果没有账号&#xff0c;点击右上角 LOGIN &#xff0c;选择 REGISTER 注册信息除了邮箱外可随意填写 登陆时&#xff0c;Username为…

文心一言 VS 讯飞星火 VS chatgpt (383)-- 算法导论24.5 3题

三、对引理 24.10 的证明进行改善&#xff0c;使其可以处理最短路径权重为 ∞ ∞ ∞ 和 − ∞ -∞ −∞ 的情况。引理 24.10(三角不等式)的内容是&#xff1a;设 G ( V , E ) G(V,E) G(V,E) 为一个带权重的有向图&#xff0c;其权重函数由 w : E → R w:E→R w:E→R 给出&…

Linux 服务器使用指南:从入门到登录

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; &#x1f6a9;博主致力于用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 目录 一…

【Maven】——基础入门,插件安装、配置和简单使用,Maven如何设置国内源

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 引入&#xff1a; 一&#xff1a;Maven插件的安装 1&#xff1a;环境准备 2&#xff1a;创建项目 二…

数据库基础(2) . 安装MySQL

0.增加右键菜单选项 添加 管理员cmd 到鼠标右键 运行 reg文件 在注册表中添加信息 这样在右键菜单中就有以管理员身份打开命令行的选项了 1.获取安装程序 网址: https://dev.mysql.com/downloads/mysql/ 到官网下载MySQL8 的zip包, 然后解压 下载后的包为: mysql-8.0.16-…

cocos开发QA

目录 TS相关foreach循环中使用return循环延迟动态获取类属性 Cocos相关属性检查器添加Enum属性使用Enum报错 枚举“XXX”用于其声明前实现不规则点击区域使用cc.RevoluteJoint的enable激活组件无效本地存储以及相关问题JSON.stringify(map)返回{}数据加密客户端复制文本使用客户…

flutter区别于vue的写法

View.dart 页面渲染&#xff1a; 类似于vue里面使用 <template> <div> <span> <textarea>等标签绘制页面, flutter 里面则是使用不同的控件来绘制页面 样式 与传统vue不同的是 flutter里面没有css/scss样式表&#xff0c; Flutter的理念是万物皆…

DICOM标准:DICOM标准中的公用模块、核心模块详解(一)——病人、研究、序列、参考帧和设备模块属性详解

目录 概述 1 公用病人IE模块 1.1 病人模块 2 公用的研究IE模块 2.1 常规研究模块 2.2 病人研究模块 3 公用序列IE模块 3.1 常规序列模块 3.1.1 常规序列属性描述 4 公用参考帧信息实体模块 4.1 参考帧模块 4.1.1 参考帧属性描述 5 公用设备IE模块 5.1 常规设备模…

轻松搞定项目管理!用对在线项目管理工具助你生产力翻倍!

一、引言 在线项目管理是指借助互联网平台和相关软件工具&#xff0c;对项目从启动到结束的全过程进行规划、组织、协调、控制和监督的一种管理方式。它打破了传统项目管理在时间和空间上的限制&#xff0c;使得项目团队成员无论身处何地&#xff0c;都能实时同步项目信息、协…

ERP研究 | 颜值美和道德美,哪个更重要?

摘要 道德美和颜值美都会影响我们的评价。在这里&#xff0c;本研究采用事件相关电位(ERPs)技术探讨了道德美和颜值美如何交互影响社会判断和情感反应。参与者(均为女性)将积极、中性或消极的言语信息与高吸引力或低吸引力面孔进行关联&#xff0c;并对这些面孔进行评分&#…

【Linux】从零开始使用多路转接IO --- epoll

当你偶尔发现语言变得无力时&#xff0c; 不妨安静下来&#xff0c; 让沉默替你发声。 --- 里则林 --- 从零开始认识多路转接 1 epoll的作用和定位2 epoll 的接口3 epoll工作原理4 实现epollserverV1 1 epoll的作用和定位 之前提过的多路转接方案select和poll 都有致命缺点…

利用 Feather 格式加速数据科学工作流:Pandas 中的最佳实践

利用 Feather 格式加速数据科学工作流&#xff1a;Pandas 中的最佳实践 在数据科学中&#xff0c;高效的数据存储和传输对于保持分析流程的流畅性至关重要。传统的 CSV 格式虽然通用&#xff0c;但在处理大规模数据集时速度较慢&#xff0c;特别是在反复读取和写入时。幸运的是…

[极客大挑战 2019]BabySQL 1

[极客大挑战 2019]BabySQL 1 审题 还是SQL注入和之前的是一个系列的。 知识点 联合注入&#xff0c;双写绕过 解题 输入万能密码 发现回显中没有or&#xff0c;猜测是使用正则过滤了or。 尝试双写绕过 登录成功 使用联合查询&#xff0c;本题中过滤了from&#xff0c;w…

全面解析:大数据技术及其应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 全面解析&#xff1a;大数据技术及其应用 全面解析&#xff1a;大数据技术及其应用 全面解析&#xff1a;大数据技术及其应用 大…