为什么这段 SQL 代码在 Mysql 失效了, Mysql 不是阻塞的吗?

2022-03-31 11:04:04 +08:00
 Features
判断表中是否有记录:
SELECT * FROM `order` WHERE `member_id` = 39 AND `sn` = 20220331783;
无则插入
INSERT INTO `order` SET `sn` = 20220331783 , `member_id` = 39;
有则更新
UPDATE `order` SET `sum` = `sum`+1;

实际的结果是数据库中有多条相同的 member_id 和 sn
为什么会这样呢?
Mysql 不是阻塞的吗?
4165 次点击
所在节点    问与答
46 条回复
zjj19950716
2022-03-31 11:17:26 +08:00
看到沙发还在,我准备抢一楼,有人也准备抢一楼,那么谁是一楼呢
xzh20121116g
2022-03-31 11:19:37 +08:00
90%的概率:代码没有考虑并发,跟 mysql 没关系
sun1991
2022-03-31 11:21:21 +08:00
MySQL 不是阻塞的. (陈述句)
任何上规模数据库都不可能简简单单就阻塞.
livenux
2022-03-31 11:21:44 +08:00
这个用 upsert 不就好了?
gtchan13579
2022-03-31 11:26:59 +08:00
直接用 replace into
Feiex
2022-03-31 11:27:47 +08:00
开启事务了吗,什么级别?
Features
2022-03-31 11:27:59 +08:00
@xzh20121116g
@sun1991
测试环境是单库,发出多个请求就会导致数据重复
假设有 1,2,3 个请求
请求 1 返回成功结果,这时候服务端应该把数据插入表中了
请求 2 和请求 3 应该能 SELECT 到正确的数据啊?
Features
2022-03-31 11:31:33 +08:00
@Feiex 没设置事务
Jooooooooo
2022-03-31 11:31:46 +08:00
@Features 请求 2 等待请求 1 成功再做吗?
turan12
2022-03-31 11:32:01 +08:00
使用 select for update 不知能否解决问题?
Features
2022-03-31 11:34:36 +08:00
@Jooooooooo 好像确实不是的
Ritter
2022-03-31 11:34:42 +08:00
两个请求同时进来 同时查到没有记录呗
Feiex
2022-03-31 11:36:34 +08:00
@Features mysql 执行语句默认不是阻塞的,不然数据库做不了并发;
#7 典型的事务隔离问题;

语句开启需要事务,rc 级别即可:
begin transaction;
//for update 注意是关键!!!
SELECT * FROM `order` WHERE `member_id` = 39 AND `sn` = 20220331783 for update;
INSERT INTO `order` SET `sn` = 20220331783 , `member_id` = 39;
UPDATE `order` SET `sum` = `sum`+1;
commit;
Features
2022-03-31 11:36:53 +08:00
@Ritter 是的,因为 Mysql 是远程的,把这个问题暴露出来了,以前没注意到。。。
Features
2022-03-31 11:37:29 +08:00
@Feiex 感谢
Features
2022-03-31 11:39:28 +08:00
@turan12 应该不行,因为多个请求并发,可能前一个请求的数据还 没到达服务器 /存储成功 /未更新
应该要从其他地方解决问题
wowo243
2022-03-31 11:45:31 +08:00
接口幂等问题?加个锁或者标记位,比如在 redis 中存一个 key 为 member_id+sn 的数据,接口先访问 redis 看 key 是否存在,不存在则设置 key 并执行逻辑,执行完逻辑后删除 key ;存在则等待标记位清除,再设置 key 并执行逻辑。
micean
2022-03-31 11:51:15 +08:00
sn 和 member_id 建唯一索引

然后 INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c = c+1
Pythoner666666
2022-03-31 11:52:38 +08:00
考虑下是不是异步 + 并发的问题
JeromeCui
2022-03-31 11:52:47 +08:00
@micean 这才是正确的方式

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

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

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

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

© 2021 V2EX