服务器卡顿了15秒,导致同一笔微信支付的两次通知都被处理了?
点击上方关注 “终端研发部”
设为“星标”,和你一起掌握更多数据库知识
这个是设计问题,前端和后端代码都存在问题!
对于后端来说,同一笔微信支付为什么会被通知两次?
为什么通知两次,每次去支付的时候,都能支付成功?
举一个例子例子:
创建订单时,需要减库存,如果减库存接口超时了,调用方重新调用一次(无论是否成功的执行了减库存代码),应该要保证不会多减一次库存。
一个完整的支付流程应该是这样的:
1、生成订单
这个时候生成订单并用雪花算法生成唯一id,减库存,有需要的话并触发定时任务)
2、调用微信支付统一下单API
3、生成预支付交易(远程调用的第一个接口)
4、返回预支付交易url
5、如有需要的话根据链接生成二维码图片返回给前端
6、提交链接
用户打开微信扫一扫二维码,(扫码的过程向微信客户端提交扫码链接)
7、微信客户端验证链接的有效性,返回需要用户授权
8、用户确定支付并输入密码提交授权
9、微信客户端验证授权,完成交易
10、返回支付结果,微信消息提示或者利用第三方库发送短信进行提醒
11、回调通知
微信主动给我们系统发起通知支付结果,这个时候是异步的
我来分分享一个完整的业务支付流程图:
最后
系统收到通知会修改订单的状态,修改成功后会通知微信客户端接收情况
可能会产生的问题:
网络异常的情况如同作者提问中的那样,用户收到了通知,我们的客户端因为网络问题并没有收到通知
这种情况下我们的系统会主动调用微信的系统查询订单的接口,微信客户端返回支付状态,修改我们的订单。
后端一般做幂等性操作
1、数据库唯一主键
这种方式比较简单!数据库唯一主键的实现主要是利用数据库中主键唯一约束的特性,其能保证一张表中只能存在一条带该唯一主键的记录
2、数据库乐观锁
3、防重 Token 令牌
4、分布式锁
分布式锁实现幂等性的逻辑就是,请求过来时,先去尝试获得分布式锁,如果获得成功,就执行业务逻辑,反之获取失败的话,就舍弃请求直接返回成功。
一般有两种方案:
1、利用redis原生的setnx,getnx
2、利用redis配合Lua脚本
2、利用redission第三方框架,内部集成了lua基本,脚本,支持黑白锁,比较好用!
拿 Redis 分布式锁举例
比如一个订单发起支付请求,支付系统会去 Redis 缓存中查询是否存在该订单号的 Key,如果不存在,则以 Key 为订单号向 Redis 插入。查询订单是否已经支付,如果没有则进行支付,支付完成后删除该订单号的Key。通过 Redis 做到了分布式锁,只有这次订单支付请求完成,下次请求才能进来。当然这里需要设置一个Key 的过期时间,在发生异常的时候还要注意删除 Redis 的 Key。
当然也可以参考这个:
终端研发部:五年的Java开发连幂等性都不知道?看完这篇就懂了21 赞同 · 0 评论文章
所以真对这个问题,解决起来没那么复杂!
PS:如果想学习技术,或者在学习技术的过程中有疑问,对编程方向的选择,可以来这里找小于哥,一个有思想有规划,被代码延误的心灵导师,可咨询offer的选择,职业规划,学习路线,技术开发中的问题
我是终端研发部的小于哥
@终端研发部
天专注技术开发小技巧,技术教程进阶,职场经验,面试的分享,希望我的回答能够帮助到你哈,笔芯~
回复 【idea激活】即可获得idea的激活方式
回复 【Java】获取java相关的视频教程和资料
回复 【SpringCloud】获取SpringCloud相关多的学习资料
回复 【python】获取全套0基础Python知识手册
回复 【2020】获取2020java相关面试题教程
回复 【加群】即可加入终端研发部相关的技术交流群
阅读更多
用 Spring 的 BeanUtils 前,建议你先了解这几个坑!
lazy-mock ,一个生成后端模拟数据的懒人工具
在华为鸿蒙 OS 上尝鲜,我的第一个“hello world”,起飞!
字节跳动一面:i++ 是线程安全的吗?
一条 SQL 引发的事故,同事直接被开除!!
太扎心!排查阿里云 ECS 的 CPU 居然达100%
一款vue编写的功能强大的swagger-ui,有点秀(附开源地址)
相信自己,没有做不到的,只有想不到的
在这里获得的不仅仅是技术!
喜欢就给个“在看”