请求有并发的时候,该怎么处理数据

2020-09-17 17:59:07 +08:00
 rqxiao

系统在接受第三方回调的时候, 第三方如果没有收到成功响应,每隔几秒回调,每次会同时发 2 次请求

但系统又要保证回调记录里同一个订单只要收到过回调记录就不记录剩下的回调了

那要确保间隔很短时间内,只认第一次回调的数据,请教下这个是要在程序里做处理,还是直接在数据库做处理

后台是 springboot 数据库是 mysql

当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过, 如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和 处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱

1505 次点击
所在节点    程序员
5 条回复
laminux29
2020-09-17 18:17:10 +08:00
在程序里,还是在数据库里做,要根据你们自己系统的情况来设计。

如果程序员技术是传说级,并且很勤奋,喜欢加班,那么直接在程序里做会更好,因为压力不会集中在数据库上。在程序里做,如果处理流程不是串行的,需要考虑对被处理的数据进行加锁来防止并发请求对数据的骚扰。分布式的模式下甚至还要考虑分布式锁。

如果程序员技术只是精良级,或者程序员打算偷懒,那么在数据库里做会更方便。比如写个简单的串行存储过程,然后就不用加班可以去美美地喝咖啡了。
libook
2020-09-17 18:25:55 +08:00
第三方回调的时候是否有他们的回调 id,有的话可以在存储回调数据的表里将这个 id 标为主键或唯一索引,然后每一个回调请求过来就尝试执行插入操作,失败就放弃这个请求,成功就继续调用业务逻辑。

为了防止服务刚 insert 成功就挂掉导致业务逻辑没有正确执行,可以在回调数据记录里加一个处理状态,处理成功就更新状态为成功,那么在服务重启的时候可以先去查一下有哪些未处理完成的记录,重新处理即可。可以用事务来保证数据库多次读写的原子性,避免由于程序中断或分布式处理导致的脏数据。

如果你处理回调请求的时间比较长,那么也可以用消息队列,收到第三方回调就把回调数据插入到消息队列,插入成功就立即返回给 第三方成功,这样第三方就不会持续给你发回调。后面的集群以适当的负载匀速消费队列里消息即可。
rqxiao
2020-09-17 18:30:18 +08:00
@libook 嗯 用个唯一索引来保存回调 id 的应该是可行,现在接受后的确还要处理业务逻辑也用了消息队列了
wanglulei
2020-09-17 18:32:04 +08:00
我的理解是根据订单号加个锁就好了吧。redis 分布式锁。
wangritian
2020-09-18 09:25:06 +08:00
select * from 订单表 where id = ? for update 上行锁
commit 或 rollback 解锁

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/708022

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX