当前位置: 首页 > 知识库问答 >
问题:

mysql - 如何防止并发操作时账户余额的扣费和充值冲突?

韶弘壮
2024-05-20

账户余额,充值和扣费,
怎么防止在扣费的时候拿的余额是10块钱,要扣1块钱,然后余额是9块钱
然后同一时间充值拿的余额也是10块钱,充值10块钱。应该是最后充完余额为19元,怎么防止这个并发呢,请问sql应该怎么去写

怎么防止这个并发呢

共有4个答案

舒枫涟
2024-05-20

扣费操作:

START TRANSACTION;-- 假设 user_id = 123SELECT balance FROM accounts WHERE user_id = 123 FOR UPDATE;-- 假设需要扣除金额为 1UPDATE accounts SET balance = balance - 1 WHERE user_id = 123;COMMIT;

充值操作:

START TRANSACTION;-- 假设 user_id = 123SELECT balance FROM accounts WHERE user_id = 123 FOR UPDATE;-- 假设充值金额为 10UPDATE accounts SET balance = balance + 10 WHERE user_id = 123;COMMIT;
荣晨朗
2024-05-20

最简单方案就就是通过sql来实现,比如用以下类似的sql来实现,基本能控制并发

update set money = money - 10 where id=1 and  money-10>0
严繁
2024-05-20

业务代码层面上做,通过加锁,同一时刻只允许扣费或只允许充值。

雍飞雨
2024-05-20

如果站在必须保证扣费和充值都成功的维度

  • 用悲观锁的方式实现
    使用用户id做为锁标识,例如 change:balance:userId:123
    当变更账户余额时(充值或扣费)尝试获得锁,如果获得锁成功则继续变更账户余额,否则阻塞,直到尝试获得锁实施变更账户余额操作,从而保证整个变更余额过程的原子性;
  • 队列的方式实现
    通过队列来实现串行和解耦,将扣费和充值动作都丢到FIFO队列中,在由一个消费者依次去队列中取出要执行的action,这样保证整个更余额过程是同步的(synchronized);

    当然这两种方案也可以结合使用

如果站在高性能的维度

  • 可通过乐观锁方式实现
    即在获取账户余额时同时获得此时数据的verson,
    当变更余额时加上version的判断,例如

    udpate account_balance set balance = balance + :changeNum, version = version + 1where user_id = :userId and version = :version
    :changeNum为传入的变更余额(扣1块或充值10块),
    :userId为传入的用户id,
    :version为传入的数据verison

此时,sql的响应行数为1则表示更新成,0则表示更新失败(数据已经被其他线程更新)。

 类似资料:
  • 接口说明 该接口由开发者开放给变现猫,变现猫进行调用 当用户发起余额支付请求后,变现猫将会创建一个订单,然后发起该用户的余额扣除请求给开发者。 这个请求会包含用户id,变现猫订单号,扣除的余额数等信息。开发者收到该请求后对签名进行校验。校验通过后请自行在自己系统中创建订单,并记录请求中的相关信息,同时执行用户余额扣除动作。 如果扣除成功,写入成功的参数和开发者系统的订单号,返回这个响应给变现猫。

  • 列出账户和检查余额 列出你现有的账户 在命令行输入: $ geth account list Account #0: {d1ade25ccd3d550a7eb532ac759cac7be09c2719} Account #1: {da65665fc30803cb1fb7e6d86691e20b1826dee0} Account #2: {e470b1a7d2c9c5c6f03bbaa8fa20db

  • web3.eth.getBalance()方法用来获取指定块中特定账户地址的余额。 调用: web3.eth.getBalance(address [, defaultBlock] [, callback]) 参数: address:String - 要检查余额的账户地址 defaultBlock:Number|String - 可选,使用该参数覆盖web3.eth.defaultBlock属性

  • 接口说明 该接口由开发者开放给变现猫,变现猫进行调用 不管余额扣除行为最终成功还是失败,变现猫都会向开发者发出通知。 开发者收到通知后,请以变现猫订单号 orderNum 为准进行处理,改变订单状态,如果扣除成功,开发者在系统内标记此订单为成功状态即可。如果扣除失败,开发者需要将该订单标记为失败,并将之前扣余额接口预扣的余额返还给用户。 无论接受到的结果如何,只要开发者收到该请求,请返回 ok 字

  • 问题内容: 我有一个包含URL和代表其参数的字符串的表。问题是我希望url和parameterstring是表的唯一约束-aka没有条目可以具有相同的url AND parameter string。参数字符串可以是任意长度(长于800bytes左右,这是MySql键的最大长度,因此我不能使用Unique(url,params),因为它会引发错误…)。 我曾考虑过使用触发器来执行此操作,但是如果触

  • 问题内容: 我们有三个Web服务(,,),其中每个服务映射到一个方法(在一个单独的Java类)( ,,)。 只能同时运行一项服务(即:无法在运行时运行)。但是,由于这是REST API,因此无法阻止客户端请求并发运行的服务。 在服务器上 强制 服务 不能 同时运行的最佳和最简单的方法是什么? 更新 :这是一个内部应用程序,我们的负载不会很大,只有一台应用程序服务器。 更新 :这是一个主观的问题,因