从第三方API获取信息,获取成功扣除余额1,实际执行余额扣除混乱

代码如下,正确结果应该是每获取到一个有效信息(即code==0时),用户wang余额扣除一个点,实际执行效果扣除余额不准确,获取到一次有效信息会出现扣除用户两个点或者三个点的情况。用户访问频率较高,一秒可能会访问接口3到4次。我能想到的可能是由于没有加timeout,访问原始API时信息还没有及时返回,用户又进行了下一次访问,导致扣除余额混乱。来先生指教,谢谢!
headers = {'Connection': 'close'}
src_codeurl = 'http://api.kkjkj.cn/getmsg?token=544548748455'' #原始API
                    print(src_codeurl)
                    try:
                        reponse = requests.get(src_codeurl, headers=headers, verify=False)  # 访问原始API
                    except requests.exceptions.Timeout as e:
                        result = {'code': 3, 'message': ''}
                    except requests.exceptions.ConnectionError as e:
                        result = {'code': 3, 'message': ''}
                    else:
                        result = json.loads(reponse.text)  # 解析返回json
                        print(result)
                        code = result.get('code')  # 获取code值,code值为0时说明取到有效信息
                        if code == 0:
                            sql = "update scmsg set yue=yue-1 where user =wang" #成功获取到信息,扣除用户wang相应余额
                            with db_lock:
                                db.is_connected()
                                db.cursor.execute(sql)
                            msg = result['msg']  # 获取有效信息内容
                            result = {'code': 0, 'msg': 'succ', 'Vmsg': msg}#自定义的返回格式


不应该直接修改数据库,正确的思路应该是下面这样,加锁方案不太靠谱,因为会造成数据丢失,例如,我有两次code=0,但是只保证执行了一次yue=yue-1
1.创建一个全局队列(如果是分布式,可以用 redis 或者 rocketMQ, mysql等来实现队列, 消息消费后删除),如果是单机,则使用本地队列,例如先进先出队列。
2.code == 0 时 ,写一个 存根 例如(user = wang, yue = 1) 到消息队列。
3.先进先出,或者定时任务 一条条消费存根数据。
4.根据存根消息 update scmsg set yue=yue-1 where user = wang
如果给您提供思路了,望采纳。

你可以抓包看看,到底发送了几次

1,抓包,或者设标志变量,检查发送了几次,有效获取信息几次,扣除余额几次
2,用户访问的请求,是手动发送还是自动发送,如果是自动发送,是否存在用户端设置了条件循环多次发送,或者多并发请求?
3,如果是这样,可以限制用户请求的频率,也可以对用户请求的访问地址进行比对,剔除重复的请求,把访问失败重新执行的功能放在你的程序中控制。

应该加上对操作id的记录,对一次操作仅能扣除一次,如果已经扣除就不能重复扣除,且需要增加数据库原子锁判断成功后就不能重复操作。有帮助请采纳谢谢!

这个就是典型的数据处理问题,你需要确保的是数据的原子性。如果用户访问量大,建议可以上缓存或MQ,处理后再存库。

本质上是请求重放导致的,在很早之前有一种攻击叫做重放攻击,后续各个框架都内置了相应的对策。其实你这个问题也类似于重放了,重放的本质有两个,一个是并发,一个是重复处理。并发我们应该很好解决,通过加锁实现。重复处理需要你把请求接口与某一指定的操作进行绑定,例如扣款是要绑定某一个订单的,当订单已经支付完毕时,是不能重新扣款的,所以解决这两个问题,你的问题也就解决了。

取不到返回成功信息,你再重新发送

请求都是同步的,又不是异步

增加一个判断,同一个用户还没有处理完上一次的,又重复请求的,返回提示让先不要操作,等处理完上一次的请求再操作

没有什么是抓包解决不了的,抓包,或者设标志变量,检查发送了几次,有效获取信息几次,扣除余额几次

并发加锁

你把数据交互想得太简单了,楼上已经有很多方法了。
其实归纳起来,就是需要一个唯一识别标识,用来防止重复以及并发加锁控制。至于这个东西放哪里,后端、中间件、数据库各有各的实现方式

同步获取,收单成功后,再进行下一次扣款

好像是前端高频点击导致的,前端加一个防抖节流函数防止高频点击,后台在下单前获取一个下单的唯一token,下单的时候需要这个token。后台系统校验这个 token是否有效,才继续进行下单操作
https://blog.csdn.net/weixin_42071874/article/details/90402099

最简单的办法:

  1. 前台加个节流函数, 防止用户高频点击;
  2. 后台加个redis分布式锁, 拼接用户id做redisKey, 每个用户同一时间只能请求一次这个接口, 保证接口的原子性, 问题解决;

有用记得点个采纳

进来学习一下

如果是前端校验的话,最好是加个防重复提交,但这个根治方法最好还是通过后端进行加锁等一系列措施防止请求重复提交。

可以使用任务队列的方法,入队时可以检查操作是否出现重复或者重叠
也可以对操作进行ID标识会更好

这个就是并发处理的一些问题,用数据库的X锁试试

很有可能是 支付订单回调地址的问题,注意一下这块....我感觉很有可能是这个原因, 就是业务逻辑有问题,然后一直回调不成功 一直重复去请求, 个人思路

加锁