支付功能设计及实现思路

news2024/11/17 8:22:30

支付功能设计

主要包括:订单表,订单日志表,订单队列,定时任务。

主要考虑:事务性、幂等性、安全性。

表结构设计

  • 订单表:

订单表,最主要的就是订单号、支付状态。

CREATE TABLE `t_order` (
  `fid` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自增id',
  `forder_id` varchar(35) NOT NULL COMMENT '订单号,唯一',
  `fpay_status` varchar(15) DEFAULT '00' COMMENT '00:未支付,01:支付成功,10:订单关闭,02:支付失败,03:已下单,04:申请退款,05:退款成功,06:退款失败 ',
  `fuser_id` int(11) DEFAULT NULL COMMENT '用户id',
  `ftotal_price` decimal(25,2) NOT NULL COMMENT '总价',
  `fcreate_time` datetime DEFAULT NULL COMMENT '购买时间',
  PRIMARY KEY (`fid`),
  UNIQUE KEY `idx_order` (`forder_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='订单表';

  • 订单日志表:

订单日志表,最主要的就是订单号,支付状态,操作记录,支付渠道。

 CREATE TABLE `t_order_log` (
  `fid` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自增id',
  `forder_id` varchar(35) NOT NULL COMMENT '订单号',
  `fuser_id` int(11) DEFAULT NULL COMMENT '用户id',
  `fcreate_time` datetime DEFAULT NULL COMMENT '操作时间',
  `fpay_status` varchar(15) DEFAULT '00' COMMENT '00:未支付,01:支付成功,10:订单关闭,02:支付失败,03:已下单,04:申请退款,05:退款成功,06:退款失败 ',
  `faction` tinyint(2) unsigned DEFAULT NULL COMMENT '操作记录:1,提交;2,关闭;3,第三方回调;4.前端轮询;5.后台查询第三方;6.定时任务查询',
  `fresult` text COMMENT '订单的回调结果',
  `ftotal_price` decimal(25,2) NOT NULL COMMENT '总价',
  `fpay_channel` varchar(25) DEFAULT NULL COMMENT '支付渠道。1,微信支付;2,支付宝;3,银联支付;',
  PRIMARY KEY (`fid`),
  UNIQUE KEY `idx_order` (`forder_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='订单日志表';

此文主要涉及到订单表,以及订单日志表。

略去用户表,商品表,商品详情表,商品订单关系表。

支付流程及时序图

商品系统:指的是购物网站等系统。

如果要进行"去库存"的处理,可以在第10步中进行。

支付系统:指的是提供聚合支付服务的系统,同时提供微信支付,支付宝,银联等多种支付方式。
如果项目不需要这种聚合支付系统,也可以直接对接微信支付等。

第1步,用户点击"购买";

第2步,"商品系统"展示商品信息,生成订单id;

第3步,用户选择商品信息,提交订单。

订单入Redis队列,方便定时任务主动去取订单进行支付结果查询;

第4步,访问"支付系统",并提供appId,订单id,支付回调url等;

第5步,"支付系统"返回支付的url;

第6步,"商品系统"展示支付页面,提供多种支付方式;

第7步,用户选择支付方式,进行支付;

第8步,"支付系统"通知支付结果;

第9步,"支付系统"调用支付回调url,告知支付结果详情。

支付回调,每隔一段时间就会不断地回调,比如 1/1/4/8/16/32/… 直到接收到回复为止。

这个其实就是一种重试机制。通过延时队列实现,一次回调不成功,就再次回调,直到成功为止。

第10步,根据支付状态,决定是否执行商品业务逻辑。

第11步,通知支付结果。

支付回调

第9步和第10步是整个支付模块中最重要的部分。

支付回调的接口,需要保证幂等性、事务性、安全性。

幂等性

  • Q:怎么保证订单接口的幂等性?

使用UUID生成32位数字字母组成的唯一订单号,放入缓存中。

Redis实现的方式就是将订单id作为Key,支付状态作为value,并设置一个 key 的过期时间。

如果发现缓存中已经有了同样的订单id,就视为重复,不会进行支付请求,就直接返回。

如果支付成功,则删除缓存中对应的订单id。

并发插入

  • Q:假设Redis挂掉了,怎么避免并发插入导致订单id重复?
    由于订单表中的订单id加了唯一索引,所以即使并发查询后并发插入,也不会出现订单id重复的情况。

并发更新

  • Q: 支付回调并发更新怎么处理?
  • Q: 怎么保证支付回调接口的幂等性?
  • Q: 支付系统会对发票系统进行回调,当没有支付成功时, 就会每隔一段时间进行继续回调,如何保证多次回调,只成功一次?

数据库排它锁。Select for update。性能太差,应付不了并发。

乐观锁的版本机制。添加version字段。在这种场景下太过冗余。

对于乐观锁和悲观锁的理解,详情见:https://blog.csdn.net/puhaiyang/article/details/72284702

支付场景下,更好的做法是:使用状态机制,直接利用订单表已有的支付状态。

当回调结果为支付成功,而且数据库的支付状态不是支付成功时,才将支付状态改为支付成功,并执行业务功能。

UPDATE的时候,会有行锁。
通过状态机制和唯一id去更新,UPDATE SET status=‘A’ WHERE status=‘B’,是一种乐观锁。并发更新时,能保证线程安全。

如下:

UPDATE t_order SET fpay_status='01' WHERE forder_id='xxxxx' AND fpay_status!='01'

事务性

  • Q: 怎么保证用户付款后(支付状态改变),相应的业务逻辑会执行,并且只执行一次?不多执行,也不少执行?

执行业务功能和修改支付状态,要做事务处理,保证事务性。

如果支付成功,但是后续的业务功能执行失败,就会回滚。

安全性

  • Q:如何保证支付的安全性?

数据要加密,包括商户号等信息。

支付回调接口,一定要校验商品信息/商品价格是否正确,防止薅羊毛。

订单日志表,记录下所有的操作,包括生成订单,提交订单,支付回调,支付状态,操作记录(是第三方回调,还是前端轮询,还是定时任务)等。

订单日志表,还能分析订单的整个流程,从订单的开始到结束。

万一出现订单丢失,可以通过订单日志表的记录恢复订单。

定时任务

  • Q:为什么要引入定时任务?

定时任务:为了避免支付回调不成功,出现用户付款成功,却没有执行功能服务的情况。

可以使用定时任务,主动去"支付系统"中查询订单的支付状态,这是一种补偿机制

引入定时任务后,会有很多值得思考又有趣的问题。

  • Q: 支付失败怎么办?

支付失败,订单会重新入Redis队列,进行重试。

当重试次数达到限度,给用户支付失败的提醒,并将订单出列。

当订单过期时,给用户提示订单已经过期,并将订单出列。

  • Q: 怎么保证定时任务和第三方回调接口,同时发生时,用户付一次钱,只执行一次业务功能?

同上"怎么保证支付回调接口的幂等性"

多个事务,同时执行更新,具体的分析见:

https://www.cnblogs.com/expiator/p/12084882.html

  • Q:大量的订单未支付怎么办?

假如有很多笔订单,进入Redis队列后,又一直都没有支付,那就可能会变成脏数据。

可以用另一个新的Redis队列,当失败达到一次的次数后,就用新队列来存放这些未支付或者支付失败的订单。

  • Q:如果Redis队列中,存在100万条订单,怎么处理?

开多线程往Redis队列里面取数据。

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

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

相关文章

IOday1作业

1> 使用fgets统计给定文件的行数 2> 使用fputs和fgets完成两个文件的拷贝 3> 完成注册登录功能 做个小菜单,功能1是注册功能,输入注册账户和注册密码,将账户和密码写入文件中 功能2是登录功能,提示并输入登录账户和登录…

无人机设计技术,四旋翼无人机整机及控制系统技术浅谈

四旋翼无人机的飞行控制技术是无人机研究的重点之一。它使用直接力矩, 实现六自由度(位置与姿态)控制,具有多变量、非线性、强耦合和干扰敏感的特性。此外, 由于飞行过程中,微型飞行器同时受到多种物理效应的作用,还很容易受到气流等外部环境的干扰,模型准确性和传感…

LLM 模型融合实践指南:低成本构建高性能语言模型

编者按:随着大语言模型技术的快速发展,模型融合成为一种低成本但高性能的模型构建新途径。本文作者 Maxime Labonne 利用 mergekit 库探索了四种模型融合方法:SLERP、TIES、DARE和passthrough。通过配置示例和案例分析,作者详细阐…

一线城市打工人的大龄焦虑:都市容不下躯壳,老家容不下灵魂(含华为 OD 面试原题)

互联网的大龄焦虑 今天看到一个老生常谈的话题「大龄焦虑:都市容不下躯壳,老家容不下灵魂」。 现如今,内卷已不是互联网行业专属名称,早已渗透到一线城市中的各行各业。 但地域落差对职业的影响,互联网行业还是稳稳的位…

关于YOLOv5训练结果results.txt绘制对比图

目录 用两个results.txt在一幅图中画2条对比曲线 用一个results.txt在一幅图中画多条对比曲线: 用两个results.txt在一幅图中画2条对比曲线 # -*- coding:utf-8 -*- import matplotlib.pyplot as plt import numpy as npcolumn [epoch, train_GIOU_loss, train_o…

美国CFTC启用举报奖励机制!打击人工智能投资欺诈行为

最近几周,美国监管机构对欺诈者利用人工智能 (AI) 的说法来引诱投资者实施诈骗发出警告。掌握人工智能诈骗原始信息的个人可以匿名举报 ,并有资格根据商品期货交易委员会 (CFTC) 和证券交易委员会 (SEC) 举报计划获得金钱奖励。CFTC 关于人工智能诈骗的咨…

Docker部署Halo容器并结合内网穿透实现公网访问本地个人博客

文章目录 1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤:1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 本文主要介绍如何在CentOS 7系统使…

迷你世界制作甜甜圈

local R,r20,5--中心半径(内径与外径和的1/4)、扩充半径(高的一半) local x0,y0,z00,20,0--起点坐标 local d10000--单次遍历方块数 local id600--方块id local s,all,t-1,0,0--步骤、总方块数、循环 local demath.random(2,18)/2 local x,y,z0,0,0--当前坐标 local func…

毕业神刊!1区、CCF推荐SCI,最新26天录用!6天见刊

一手刊源 • 毕业快刊 春节一过,距离2024年上半年毕业的日子近在眼前,你的毕业论文已安排投稿了吗?时间着急的作者,不妨重点关注本期小编推荐的毕业快刊:无中科院预警记录,非三大出版社,指标情…

还在为选择办公软件而烦恼吗?不妨试试ONLYofficeV8.0

目录 一.优势一DOC 1.丰富的文字处理功能 2.按用户既定的规则编辑 3.使用AI助手 4.保持创意 5.深入分析文本 6.改善团队工作流程 7.轻松对比文档 8.扩展编辑功能 二.优势二sheet 1.数据分析 2.轻松实现精准计算 3.轻松分析数据 4.可视化呈现数据 5.增强团队协作…

通过盲注脚本复习sqllabs第46关 order by 注入

Less-46 从本关开始,我们开始学习 order by 相关注入的知识。本关的 sql 语句为$sql "SELECT * FROM users ORDER BY $id";尝试?sort1 desc或者 asc,显示结果不同,则表明可以注入。(升序 or 降序排列)从上述的 sql 语句中我们可以…

Netty-初体验

Netty 引入依赖服务端服务端处理读写业务的Handler客户端实现客户端handler Netty具备设计优雅、使⽤⽅便、性能强劲等优点&#xff0c; 引入依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>…

CVE-2024-0918 TEW-800MB RCE漏洞分析

漏洞描述 固件版本为1.0.1.0的TEW-800MB路由器存在命令注入漏洞。如果攻击者获得了web管理权限&#xff0c;他们可以将命令注入到httpd未知函数中的post请求参数DeviceURL中&#xff0c;从而获得shell权限。。 参考链接 TEW-800MB (notion.site)https://warp-desk-89d.notio…

盘点那些世界名校计算机专业采用的教材

清华、北大、MIT、CMU、斯坦福的学霸们在新学期里要学什么&#xff1f;今天我们来盘点一下那些世界名校计算机专业采用的教材。 书单目录 1.《深入理解计算机系统》&#xff08;原书第3版&#xff09;2. 《算法导论》&#xff08;原书第3版&#xff09;3. 《计算机程序的构造和…

【已解决】Zip压缩文件设置了密码怎么办?

Zip是一种常见的压缩格式文件&#xff0c;文件还可以设置密码保护。那设置了密码的Zip文件要如何打开呢&#xff1f;不清楚的小伙伴一起来看看吧。 想要打开带密码的Zip文件&#xff0c;我们需要用到适用于Zip格式的解压缩软件&#xff0c;比如WinRAR或者7-Zip软件都是可以的。…

【数据结构】_队列

目录 1.概念 2.队列的使用 3.队列模拟实现 4.循环队列 5.双端队列 6.栈与队列的互相实现 6.1 用队列实现栈 6.2 用栈实现队列 1.概念 &#xff08;1&#xff09;队列是只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff1b; &am…

PyTorch深度学习实战(37)——CycleGAN详解与实现

PyTorch深度学习实战&#xff08;37&#xff09;——CycleGAN详解与实现 0. 前言1. CycleGAN 基本原理2. CycleGAN 模型分析3. 实现 CycleGAN小结系列链接 0. 前言 CycleGAN 是一种用于图像转换的生成对抗网络(Generative Adversarial Network, GAN)&#xff0c;可以在不需要配…

分布式事务-CAP定理+BASE理论+解决方案(两阶段提交+TCC事务)

事务就是指一个操作单元&#xff0c;操作单元中的所有操作要么同时成功要么同时失败。单体项目中的事务一般都是使用数据库提供的事务机制来完成的&#xff0c;但是分布式事务的事务参与者位于不同的节点上&#xff0c;也就是分布在不同的服务器上。分布式事务的最大问题就是各…

安卓游戏开发之音频技术优劣分析

一、引言 在安卓游戏开发中&#xff0c;音频处理技术扮演着至关重要的角色&#xff0c;它不仅能够增强游戏的沉浸感和玩家体验&#xff0c;还能通过声音效果传达关键的游戏信息。以下将对几种常见的安卓游戏音频处理技术进行优劣分析&#xff0c;并结合应用场景来阐述其特点。 …

Jmeter之内置函数__property和__P的区别

1. __property函数 作用 读取 Jmeter 属性 语法格式 ${__property(key,var,default)} 参数讲解 小栗子 ${__property(key)} 读取 key 属性如果找不到 key 属性&#xff0c;则返回 key&#xff08;属性名&#xff09; ${__property(key,,default)} 读取 key 属性如果找不到 k…