ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

支付功能设计及实现思路

2020-05-11 09:56:41  阅读:564  来源: 互联网

标签:COMMENT 回调 订单 支付 思路 NULL id 功能设计


支付功能设计

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

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

表结构设计

  • 订单表:

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

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: 怎么保证支付回调接口的幂等性?

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

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

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

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

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

sql如下:

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

事务性

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

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

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

安全性

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

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

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

订单日志表,记录下所有的操作,包括生成订单,提交订单,支付回调,支付状态等。

定时任务

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

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

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

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

  • Q: 支付失败怎么办?

支付失败,订单会重新入Redis队列,进行重试。当重试次数达到限度,给用户支付失败的提醒。

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

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

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

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

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

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

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

可选方案

  • 订单入缓存,key为订单id,value为支付状态。key已存在表明是重复订单,就直接返回,支付成功则删除缓存。

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

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

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

拓展

并发更新。事务。

标签:COMMENT,回调,订单,支付,思路,NULL,id,功能设计
来源: https://www.cnblogs.com/expiator/p/12867242.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有