

新闻资讯
技术学院高并发下防超卖需用SELECT...FOR UPDATE行锁,必须命中索引;无强序需求可用唯一约束+ON DUPLICATE KEY UPDATE;严格FIFO应交由Redis队列处理,避免依赖AUTO_INCREMENT或时间戳排序。
SELECT ... FOR UPDATE 实现行级排队在高并发更新同一行数据时(比如库存扣减),直接 UPDATE 可能导致超卖。必须让请求串行化处理该行。核心是先查再锁,且查询必须命中索引——否则会升级为表锁或锁住不相关记录。
SELECT stock FROM goods WHERE id = 123 FOR UPDATE 必须基于主键或唯一索引,否则 MySQL 可能加间隙锁(Gap Lock)锁住更大范围UPDATE 和 COMMIT,否则锁会持续到事务结束,拖慢整体吞吐setQueryTimeout(),避免某请求卡死导致后续全部阻塞INSERT ... SELECT ... ON DUPLICATE KEY UPDATE 做无锁队列写入当“排队”目标不是强一致性顺序,而是防止重复处理(如防重下单),可用唯一约束 + 插入冲突回退替代显式加锁。它比 FOR UPDATE 更轻量,但不保证全局执行顺序。
order_no)加 UNIQUE 索引INSERT INTO queue_log (order_no, status, created_at) VALUES ('NO123', 'pending', NOW()) ON DUPLICATE KEY UPDATE status = VALUES(status)
MySQL 本身不提供消息队列能力,纯靠数据库实现严格 FIFO 容易成为瓶颈。更常见的做法是把“排队逻辑”下沉到 Redis,MySQL 只负责最终状态落地。
LPUSH queue:order 入队,BRPOP queue:order 0 阻塞取任务,天然保序AUTO_INCREMENT 或时间戳排序请求很多人误以为插入时的自增 ID 或 NOW() 时间就能代表请求到达顺序,实际在并发下完全不可靠。
AUTO_INCREMENT 在批量插入、InnoDB 的 innodb_autoinc_lock_mode=2(默认)下可能跳号、乱序分配NOW() 精度只有秒级(5.6 及以前)或微秒级(5.7+),但同一微秒内仍可能有多个请求,且写入落盘顺序≠执行顺序-- 错误示例:以为按 id 升序就是请求顺序 SELECT * FROM order_log ORDER BY id ASC; -- 实际可能漏掉未提交事务的记录,或被 gap lock 影响可见性
真正需要顺序控制的地方,必须显式引入锁、队列或版本号机制,而不是依赖数据库的隐式行为。