关于 mysql 并发的问题又来了

2022-04-03 18:54:19 +08:00
 Features
要扣除用户余额 100 ,以前大学学过一点 java EE,正常就是
1.SELECT `余额` FROM user;
2.余额 >= 100 则 UPDATE
3.否则提示用户余额不足

现在请求并发太高,查询的余额还没来得及更新,导致超扣了

我目前的解决办法:
1.把扣除余额请求放到自己实现的 redis 队列里
2.使用一个 thread 定时轮询队列,多 thread 我怕又出现并发问题,0.5s 轮询一次,处理过程中停止轮询
保证只有一个线程在处理数据
3.客户端开个 socket 连接,做一些加载动画,等待跳转的动作,等 socket 更新数据

我感觉这样就很不优雅
有什么能在 mysql 层面解决这个问题的吗?
3467 次点击
所在节点    MySQL
28 条回复
Aoang
2022-04-03 19:00:17 +08:00
事务呢?有事务不用,自己造个三角形的轮子
Jooooooooo
2022-04-03 19:01:20 +08:00
先用 redis 拦一遍是可以的

最终在 update 里加个 where 余额>100 的条件啊
Features
2022-04-03 19:06:15 +08:00
@Jooooooooo 哦哦,对,这样应该是可以的
Features
2022-04-03 19:18:51 +08:00
实测是我太弱智了
应该先 update where 余额 >= 100 ,这个语句不成功就 trhow Exception 就好了
成功则添加记录等动作
javapythongo
2022-04-03 19:21:45 +08:00
行锁、乐观锁吧
broadliyn
2022-04-03 19:41:28 +08:00
update user set balance=balance-100 where id=1 and balance>=100;
xuanbg
2022-04-03 19:57:11 +08:00
6 楼正解
kingjpa
2022-04-03 20:42:42 +08:00
我一般是 ,先锁,开启事务 然后更新, 后提交事务, 测过并发,没问题的。
其实 redis 也可以,但多一个服务就多一个不确定性。
sunnyandpenta
2022-04-03 20:49:07 +08:00
start transaction
1.SELECT balance FROM user where user_id = #{userId} for update;
2. int affectRows = update user set balance=balance-100 where user_id = #{userId} and balance>=100;
3.
if(affectRows > 0){
commit;
}else{
rollback;
}
stonewu
2022-04-03 21:21:02 +08:00
update user set balance = balance - 你要扣除的金额 where balance - 你要扣除的金额 >= 0 and id=用户 ID;
jasonkayzk
2022-04-03 21:25:43 +08:00
这么经典的问题,用乐观锁不就解决了:

update user set balance=balance-? where id=? and balance>=?;
documentzhangx66
2022-04-03 21:33:35 +08:00
当你还不懂使用事务的情况下,这种涉及到金钱的操作,还是建议使用 Oracle 。

一来 Oracle 稳,第二是 Oracle 这种扣钱的案例,能搜到很多例子...
iseki
2022-04-03 21:43:41 +08:00
如果你对事务不太了解,建议切换至 Serializable 隔离等级
kekxv
2022-04-03 21:44:16 +08:00
时间有要求?没有的话有个最简单的,直接用 redis 锁这个 ID 就行
iseki
2022-04-03 21:44:31 +08:00
哦,如果完全不会用事务,那啥隔离等级也没用···这倒是忘了
liangkang1436
2022-04-03 21:49:35 +08:00
你应该用事务和锁来实现,而不是用尽办法保证只有一个线程在更新数据库,因为数据库不是你一个人在用,别人也在可能操作这个表
512357301
2022-04-03 21:50:53 +08:00
6 楼正解。
还有就是楼主很明显在用代码的栈或者数组思维搞数据库,却忘了数据库最擅长增删改查了,尤其是 MySQL
liangkang1436
2022-04-03 21:51:25 +08:00
我记得 MySQL 默认的事务级别就是可重复读
Features
2022-04-03 22:02:02 +08:00
@liangkang1436 确实,是我刚学这个,遇到的问题太初级了
Features
2022-04-03 22:05:12 +08:00
@Aoang
@iseki
@liangkang1436

请教下,这种高并发的情况下,和事务有关系吗?
前一个请求中有未执行完成的事务,后面的 N 个请求又启用了 N 个事务
还是说 Mysql 的机制中只允许存在一个事务?

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

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

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

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

© 2021 V2EX