V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rqxiao
V2EX  ›  程序员

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

  •  
  •   rqxiao · 2020-09-17 17:59:07 +08:00 · 1482 次点击
    这是一个创建于 1513 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    后台是 springboot 数据库是 mysql

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

    5 条回复    2020-09-18 09:25:06 +08:00
    laminux29
        1
    laminux29  
       2020-09-17 18:17:10 +08:00   ❤️ 1
    在程序里,还是在数据库里做,要根据你们自己系统的情况来设计。

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

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

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

    如果你处理回调请求的时间比较长,那么也可以用消息队列,收到第三方回调就把回调数据插入到消息队列,插入成功就立即返回给 第三方成功,这样第三方就不会持续给你发回调。后面的集群以适当的负载匀速消费队列里消息即可。
    rqxiao
        3
    rqxiao  
    OP
       2020-09-17 18:30:18 +08:00
    @libook 嗯 用个唯一索引来保存回调 id 的应该是可行,现在接受后的确还要处理业务逻辑也用了消息队列了
    wanglulei
        4
    wanglulei  
       2020-09-17 18:32:04 +08:00   ❤️ 1
    我的理解是根据订单号加个锁就好了吧。redis 分布式锁。
    wangritian
        5
    wangritian  
       2020-09-18 09:25:06 +08:00   ❤️ 1
    select * from 订单表 where id = ? for update 上行锁
    commit 或 rollback 解锁
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2724 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 11:57 · PVG 19:57 · LAX 03:57 · JFK 06:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.