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

test
2024-06-19
如果站在必须保证扣费和充值都成功的维度
- 用悲观锁的方式实现使用用户id做为锁标识,例如
change:balance:userId:123
当变更账户余额时(充值或扣费)尝试获得锁,如果获得锁成功则继续变更账户余额,否则阻塞,直到尝试获得锁实施变更账户余额操作,从而保证整个变更余额过程的原子性; 队列的方式实现通过队列来实现串行和解耦,将扣费和充值动作都丢到FIFO队列中,在由一个消费者依次去队列中取出要执行的action,这样保证整个更余额过程是同步的(synchronized);
当然这两种方案也可以结合使用
如果站在高性能的维度
可通过乐观锁方式实现即在获取账户余额时同时获得此时数据的verson,当变更余额时加上version的判断,例如
udpate account_balance set balance = balance + :changeNum, version = version + 1 where user_id = :userId and version = :version
:changeNum为传入的变更余额(扣1块或充值10块),:userId为传入的用户id,:version为传入的数据verison
此时,sql的响应行数为1则表示更新成,0则表示更新失败(数据已经被其他线程更新)。
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容