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

PHP +mysql 应用怎么防止重复插入

  •  
  •   shenmeshibanjiao · 2017-10-31 16:13:00 +08:00 · 3960 次点击
    这是一个创建于 2578 天前的主题,其中的信息可能已经有所发展或是发生改变。
    1、我有一个 API,可以转账发红包之类的,余额是调用别人的 API 获取的,她的 API 没有判断是否余额充足,所以可能出现负数的情况。所以每次操作是我通过调用他的余额的 API 去判断当前操作是否是 余额充足的。
    2、APP 端快速点击的时候,可能会出现负数的情况,数据库插入了很多时间戳相同的记录。
    这种情况应该怎么解决呀。
    20 条回复    2017-11-01 16:47:28 +08:00
    tradzero
        1
    tradzero  
       2017-10-31 16:53:41 +08:00
    有个很丑的实现 app 端请求的时候把时间戳带上 然后后端请求完成之后把这个时间戳放到 cache 里 然后每次这个 api 请求的时候判断时间戳在不在 cache 里 如果在就直接返回失败 这样就可以避免快速点击的问题 至于防止重复插入 由于你没办法查询余额是否充足.. 理论上是没什么办法避免的吧
    abcfyk
        2
    abcfyk  
       2017-10-31 16:57:51 +08:00
    1. 前端应有请求队列。
    2. 后端所有这种和钱有关的,全部上事务
    shenmeshibanjiao
        3
    shenmeshibanjiao  
    OP
       2017-10-31 17:02:10 +08:00
    @abcfyk 这个订单表都是用了事务的。我大概的流程是这样的,判断交易密码、调用 API 获取余额,判断余额是否充足,之后开启事务、生成订单、然后再是转账 成功了在 commit 否则就 rollback .但是现在还是有现在的情况的,连续点击多次请求,多条订单记录,余额可能出现负数。
    shenmeshibanjiao
        4
    shenmeshibanjiao  
    OP
       2017-10-31 17:03:04 +08:00
    @tradzero 谢谢老哥,我看我的订单表的时间戳都是一样的- -.
    tabris17
        5
    tabris17  
       2017-10-31 17:07:20 +08:00
    使用 token。一动作一令牌
    klgd
        6
    klgd  
       2017-10-31 17:08:10 +08:00
    余额是在哪个环节扣的?
    另外 上游 API 有问题 你作为下游应用也不可能保证没问题的
    qiuyk
        7
    qiuyk  
       2017-10-31 17:09:26 +08:00
    shenmeshibanjiao
        8
    shenmeshibanjiao  
    OP
       2017-10-31 17:09:26 +08:00
    @klgd 我大概的流程是这样的,判断交易密码、调用 API 获取余额,判断余额是否充足,之后开启事务、生成订单、然后再是转账 成功了在 commit 否则就 rollback .
    silentoy
        9
    silentoy  
       2017-10-31 17:10:20 +08:00
    @shenmeshibanjiao 金额字段应该设置成无符号的,这样 update 的时候如果金额小于订单金额就会失败,从而触发 rollback
    R18
        10
    R18  
       2017-10-31 17:11:49 +08:00
    我觉得这应该是他解决的问题不应该是你
    Redis incr 不知可否解决你的问题
    mahone3297
        11
    mahone3297  
       2017-10-31 17:12:23 +08:00
    @abcfyk 都说了,请求队列。那就不可能出现为负数的情况。
    你应该,每次处理转账的时候,都去请求判断余额。[请求判断余额,扣减]这整个是一个事务,这是一个原子。
    shenmeshibanjiao
        12
    shenmeshibanjiao  
    OP
       2017-10-31 17:13:42 +08:00
    @silentoy 因为余额都是获取 API 的,所以我的数据库是没有存储余额的,这样的话我是否可以尝试一下增加余额,每次操作之后再去获取余额存进去 ^_^ ,谢谢老哥。
    SP00F
        13
    SP00F  
       2017-10-31 17:14:04 +08:00
    开了事务的话,检查一下事务级别。把事务级别调整一下再测试。

    出现负数是因为脏读了。
    Sikoay
        14
    Sikoay  
       2017-10-31 17:14:37 +08:00 via Android
    事务判断余额是不是就能解决余额为负
    silentoy
        15
    silentoy  
       2017-10-31 17:18:10 +08:00
    @shenmeshibanjiao 如果余额是通过 API 获取的话,确实如 @klgd 所说,事务的控制应该是在上游的余额 API 端控制了,你这边很难处理
    klgd
        16
    klgd  
       2017-10-31 17:31:43 +08:00
    @shenmeshibanjiao #8 “转账”是指请求 API 去扣余额吗?
    你这个逻辑设计的有问题啊,如果你这边失败了,扣余额成功了怎么办?
    irory
        17
    irory  
       2017-10-31 17:37:11 +08:00
    来一发分布式锁 ,比如 redis lock,就能解决了呀 !
    FYK
        18
    FYK  
       2017-10-31 17:40:28 +08:00 via iPhone
    @abcfyk。。。好巧
    shenmeshibanjiao
        19
    shenmeshibanjiao  
    OP
       2017-11-01 11:42:49 +08:00
    @klgd 老哥,那该怎么弄~
    klgd
        20
    klgd  
       2017-11-01 16:47:28 +08:00
    @shenmeshibanjiao #19 我不清楚你们的余额是什么概念,为什么下订单时扣除,有没有可能在订单过程中不与余额交互,然后在其他逻辑里处理余额
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5293 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 07:33 · PVG 15:33 · LAX 23:33 · JFK 02:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.