update语句默认加行级锁,但where条件必须命中索引,否则会全表扫描并逐行加锁,等效于表级锁。

UPDATE 语句默认加什么锁?
MySQL InnoDB 下,UPDATE 默认走行级锁,但前提是 WHERE 条件命中索引;否则会升级为表级锁(实际是全表扫描 + 每行加锁,效果等同于锁全表)。
常见错误现象:UPDATE users SET status = 1 WHERE name = 'alice' 执行极慢、阻塞其他事务,查发现 name 字段没索引。
- 必须确认 WHERE 中所有字段都有对应索引,复合条件优先用联合索引
- 用
EXPLAIN看执行计划,确保type是ref或const,不是ALL - UPDATE 带 LIMIT 时,InnoDB 仍会对扫描到的所有行加锁(哪怕只改一行),这点容易被忽略
SELECT ... FOR UPDATE 和 UPDATE 锁行为差异
SELECT ... FOR UPDATE 和 UPDATE 都加临键锁(Next-Key Lock),但触发时机和范围不同:前者在读阶段就锁住记录+间隙,后者在写入前才加锁,且仅锁最终命中的行(含间隙)。
使用场景:需要先查再判再改的业务逻辑(如库存扣减),若用普通 SELECT + UPDATE,中间可能被并发修改;但直接上 SELECT ... FOR UPDATE 又可能锁得过宽。
- 如果 WHERE 条件能唯一确定一行(主键或唯一索引),
SELECT ... FOR UPDATE和UPDATE锁范围基本一致 - 若条件不唯一(如
WHERE status = 0),SELECT ... FOR UPDATE会锁住所有匹配行及其间隙,而UPDATE只锁实际更新的行(但扫描过程仍可能触发间隙锁) - 注意隔离级别影响:READ COMMITTED 下
SELECT ... FOR UPDATE不加间隙锁,但UPDATE仍加(除非关闭innodb_locks_unsafe_for_binlog,不推荐)
死锁是怎么被 UPDATE 撞出来的?
死锁不是锁多了,而是多个事务以不同顺序访问相同资源。最典型的是两个事务分别按不同索引顺序 UPDATE 同一批行。
2010.09.03更新优化前台内核处理代码;优化后台内核、静态生成相关代码,生成速度全面提升;修改前台静态模板中所有已知错误;修正后台相关模块所有已知错误;更换后台编辑器,功能更强大;增加系统说明书。免费下载、免费使用、完全无限制。完全免费拥有:应广大用户要求,千博网络全面超值发布企业网站系统个人版程序包:内含Flash动画源码、Access数据库程序包、SQL数据库程序包。全站模块化操作,静态
常见错误现象:应用报错 Deadlock found when trying to get lock; try restarting transaction,但单条语句单独执行完全正常。
- 检查事务中所有 SQL 的 WHERE 条件是否都走同一索引,避免一个走
idx_a、另一个走idx_b - UPDATE 多行时,务必按主键升序(或固定顺序)组织数据,例如先
ORDER BY id再批量更新 - 不要在一个事务里混用 SELECT ... FOR UPDATE 和 UPDATE —— 它们锁粒度和释放时机不同,极易形成环路
UPDATE 影响行数为 0 还会加锁吗?
会。只要 WHERE 条件走索引,InnoDB 就会对匹配的索引记录(包括“不存在但符合范围”的间隙)加锁,哪怕最终没更新任何行。
性能影响:这种“空锁”常被忽视,却会导致其他事务在该间隙插入失败,尤其在高并发 INSERT 场景下引发明显阻塞。
- 用
SELECT ... LOCK IN SHARE MODE或SELECT ... FOR UPDATE配合ROW_COUNT()判断是否存在,比盲目UPDATE更可控 - 如果业务允许,把“不存在则插入”逻辑改用
INSERT ... ON DUPLICATE KEY UPDATE,它对唯一冲突路径的加锁更轻量 - 监控
Innodb_row_lock_time_avg和Innodb_deadlocks,长期偏高就要查空 WHERE 是否误锁间隙
锁的边界从来不在语句表面,而在索引结构、执行路径和事务包裹方式里。调参不如理清这三者的咬合关系。









