为什么这段 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 不是阻塞的吗?
3939 次点击
所在节点    问与答
46 条回复
Features
2022-03-31 11:54:14 +08:00
最终解决办法:
在缓存中先预存 key = sn+member_id 的组合,
同时查询数据库 sn+member_id 记录条数,
如果缓存 key 的值不为空,但记录为 0 ,则返回提示: 您的手速太快了

想到更优雅的,但没时间做的解决办法:
把请求整合到一个队列中,稳定进出,应该也能解决
Features
2022-03-31 11:54:44 +08:00
@wowo243 是的,就是这个问题
Features
2022-03-31 12:33:16 +08:00
后续:
并发太高时,甚至连缓存都来不及生成
根据 @micean 的方法建立 unique key
在业务中捕获 1062 Duplicate entry 错误
调整业务代码,最终成功
Danswerme
2022-03-31 13:30:09 +08:00
学习到了,收藏下。
koloonps
2022-03-31 13:31:35 +08:00
@Features 什么叫并发太高时,甚至连缓存都来不及生成?
CEBBCAT
2022-03-31 14:18:06 +08:00
你这不是不会用数据库,是根本还没学过。找一本适合初学者的书吧

关于并发,要理解程序的并发模型才能比较好地写出健壮的代码,不然就会闹出先 SELECT 再 INSERT 的笑话

看到你是前端转后端?加油!
CEBBCAT
2022-03-31 14:19:27 +08:00
看到楼上问的“什么叫并发太高”,忍不住再发一条,你还是再系统地学学 Redis 在并发方面的用法吧,别是又先 GET 再 SET ,正确的用法是 SETNX
lawler
2022-03-31 14:32:00 +08:00
看到 16 楼才出现正确答案,着实让我震惊。
yor1g
2022-03-31 14:38:05 +08:00
要加数据库唯一索引
查-> 没有 -> 插入
查-> 有 -> 更新
查-> 没有 -> 插入 -> 唯一提示失败 -> 再查 -> 更新
或者用 redis 锁
lawler
2022-03-31 15:48:25 +08:00
@lawler #28 订正,是 18 楼。😀
xzh20121116g
2022-03-31 16:17:50 +08:00
h82258652
2022-03-31 16:38:07 +08:00
如果业务上还有软删除这种的话,那就没法加唯一了
还是搞个锁吧
Features
2022-03-31 17:01:20 +08:00
@CEBBCAT 我是在学习后端,摸鱼时间偷偷学习下
Features
2022-03-31 17:06:08 +08:00
@CEBBCAT 请教下,用 rocketmq 能否完美解决这种问题?
回想安卓中涉及到这种问题,也是使用队列处理的
br00k
2022-03-31 17:22:03 +08:00
这种避免的最佳方式就是增加唯一索引,从源头杜绝产生异常数据的可能。
wxdiy
2022-03-31 17:37:55 +08:00
@br00k 这儿才正确哇,用锁又引入了新的问题了
gamexg
2022-03-31 17:46:08 +08:00
这种需求我会加唯一索引。


@h82258652 #32 我这边是把软删除的时间字段也加到唯一索引里面,达到唯一的目的。
LinsVert
2022-03-31 17:56:46 +08:00
有时候可能不是所谓的“并发“,可能是前端没有做按钮拦截,可能出现双击操作,从而请求会几乎同一时间到达。
Features
2022-03-31 17:58:03 +08:00
后续的后续:
因为 sn 是可预期的,所以做一个 task ,提前把用户的数据加热到数据表中
此业务环境下,不再对数据进行 SELECT 和 INSERT 操作,只要 UPDATE 就可以了
性能瞬间提升了很多
Features
2022-03-31 17:58:57 +08:00
@LinsVert 这就是模拟并发啊,这种不可能要求前端做的
我自己就是前端

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

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

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

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

© 2021 V2EX