账户余额,充值和扣费,
怎么防止在扣费的时候拿的余额是10块钱,要扣1块钱,然后余额是9块钱
然后同一时间充值拿的余额也是10块钱,充值10块钱。应该是最后充完余额为19元,怎么防止这个并发呢,请问sql应该怎么去写
怎么防止这个并发呢
账户余额,充值和扣费,
怎么防止在扣费的时候拿的余额是10块钱,要扣1块钱,然后余额是9块钱
然后同一时间充值拿的余额也是10块钱,充值10块钱。应该是最后充完余额为19元,怎么防止这个并发呢,请问sql应该怎么去写
怎么防止这个并发呢
扣费操作:
START TRANSACTION;
-- 假设 user_id = 123
SELECT balance FROM accounts WHERE user_id = 123 FOR UPDATE;
-- 假设需要扣除金额为 1
UPDATE accounts SET balance = balance - 1 WHERE user_id = 123;
COMMIT;
充值操作:
START TRANSACTION;
-- 假设 user_id = 123
SELECT balance FROM accounts WHERE user_id = 123 FOR UPDATE;
-- 假设充值金额为 10
UPDATE accounts SET balance = balance + 10 WHERE user_id = 123;
COMMIT;
最简单方案就就是通过sql来实现,比如用以下类似的sql来实现,基本能控制并发
update set money = money - 10 where id=1 and money-10>0
5 回答3.2k 阅读✓ 已解决
3 回答3.6k 阅读✓ 已解决
2 回答2.8k 阅读✓ 已解决
1 回答2.4k 阅读✓ 已解决
1 回答2.3k 阅读✓ 已解决
5 回答1.4k 阅读
3 回答1.2k 阅读✓ 已解决
如果站在必须保证扣费和充值都成功的维度
使用用户id做为锁标识,例如
change:balance:userId:123
当变更账户余额时(充值或扣费)尝试获得锁,如果获得锁成功则继续变更账户余额,否则阻塞,直到尝试获得锁实施变更账户余额操作,从而保证整个变更余额过程的原子性;
队列的方式实现
通过队列来实现串行和解耦,将扣费和充值动作都丢到FIFO队列中,在由一个消费者依次去队列中取出要执行的action,这样保证整个更余额过程是同步的(synchronized);
如果站在高性能的维度
可通过乐观锁方式实现
即在获取账户余额时同时获得此时数据的verson,
当变更余额时加上version的判断,例如
此时,sql的响应行数为1则表示更新成,0则表示更新失败(数据已经被其他线程更新)。