高并发下怎么做余额扣减?

2022-11-25 17:10:18 +08:00
 hhhhhh123

这种场景 数据库 是不是只能加锁啊?
假设 数据库中有两个表 一个是流水表 也就是扣款用, 一个是 userinfo 就是余额在这看
那么并发场景下。怎么保证余额是>0 且数据无误。

我的想法是。1 查询余额 如果减去后余额 >=0 则插入扣款后的余额, 这个过程中加锁。 但是这种如果是并发高一点的话是不是很慢啊?

各位有这块的经验吗? 希望可以指点一下。或者也可以讲解一下你们公司的扣款逻辑是啥? 是如何做的 ?

7469 次点击
所在节点    程序员
41 条回复
liangliplusss
49 天前
两个方案
方案一: 悲观锁
consume(var accountId,var amount) {
//先查询余额
"select accountId,balance from xxx where accountId = $accountId for update";
//计算
$new_balance = $old_balance - $amount;
update xxx balance = $new_balance where accountId = $accountId
}

方案二: 乐观锁
consume(var accountId,var amount) {
flag = false,retires = 3
// CAS + 重试
while(!flag && retries > 0) {
flag = consume0(accountId,amount);
retries--;
}

}

boolean consume0(var accountId,var amount) {
//先查询余额(只是查询不加锁)
"select accountId,balance from xxx where accountId = $accountId";
//计算
$new_balance = $old_balance - $amount;
row = update xxx balance = $new_balance where accountId = $accountId and balance = $old_balance
return row == 1;
}

备选方案:(高并发,单个用户消费并发超过 1000 )缓存 + 消息中间件,
用户消费操作是扣减缓存中余额(注意这里原子性查询和扣减两个动作,例如 redis 可以使用 lua ), 扣减成功发送消息到消息队列更新数据库。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/897920

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX