同步更新

问题描述 投票:0回答:3

我正在构建一个处理钱包的应用程序。我这个钱包有现金入账现金出账
当这个钱包的 + 或 - 发生更新时我遇到了问题。
看场景:

用户进行兑现,系统会检索该钱包的余额,如下所示:

select * from Wallet where idUser = x;

所以上面的查询返回钱包,并且*获取“余额”列并这样做

wallet.balance += amount;

此后,我将进行更新以插入该钱包的新“余额”并执行此操作

update Wallet set balance = balanceVar where idWallet = x;

到目前为止,一切看起来都很好,但是当我们处理并发现金进出时,在这种情况下更好的情况是什么。
将其放入队列中?
更新时锁定表?
这是我第一次处理这样的系统,我真的很困惑该怎么办。

mysql sql algorithm concurrency
3个回答
2
投票

您的

SELECT
然后
UPDATE
方案直接导致竞争条件,其中两个进程可以选择相同的数据,然后执行相同的更新,从而导致发生两次更新但只记录一次的不一致。

避免这种情况的方法是使用原子操作(即不可分割的操作)。

在您的情况下,您应该直接更新钱包:

update Wallet set balance = balance+10 where idWallet = 'x';

此更新将在另一个进程执行另一次更新之前完全完成。

你可以进一步推进这个想法。对于提款,只有当余额大于或等于提款时,您才能更新钱包:

update Wallet set balance = balance-10 where idWallet = 'x' and balance >= 10;

您可以测试

ROW_COUNT()
,看看操作是否成功。 PHP 为此提供了
mysqli_affected_rows()
PDOStatement::rowCount()


1
投票

在这些情况下最好的办法就是使用交易来保证信息的完整性,这样管理者就可以处理在操作信息时可能出现的冲突


0
投票

TLDR; 您可以使用排队机制来确保更新操作的一致性。

简短示例: 使用 Redis 队列:

出版商:

// Increase or decrease wallet balance, or maybe multiple operations
$redis->lpush('my-queue', json_encode([1234 => '+1']); // ex. 1234 is wallet id 
$redis->lpush('my-queue', '-1');
// ...etc

订阅者:

while (true) {
   $queueData = $redis->rpop('my-queue');
   if (!empty($data)) {
      $data = json_decode($queueData);
      // process increment or decrement wallet balance based on consumed data
   }
}

这将根据排队数据相应更新钱包余额。您可以使用任何排队工具(例如 Redis、RabbitMQ 等)来实现此目的。

© www.soinside.com 2019 - 2024. All rights reserved.