rc级别下update仍锁不相关行,是因为where条件未走索引导致全表扫描并逐行加行锁,效果等同锁表;即使关闭间隙锁,无索引时锁范围仍极大。

READ COMMITTED 能减少锁冲突,但不是设了就自动生效——它只对当前事务起作用,且依赖 binlog_format = ROW 和索引质量。没配对或没走索引时,照样锁一大片。
为什么 RC 级别下 UPDATE 还会锁住不相关行
RC 关闭了间隙锁(Gap Lock),但只限于“真正命中的索引行”。如果 WHERE 条件没走索引,InnoDB 仍要全表扫描,为每行加行锁,效果等同锁表。
- 用
EXPLAIN SELECT ... FOR UPDATE或EXPLAIN UPDATE确认key字段非NULL,rows值接近实际影响行数 - 避免隐式转换:
WHERE user_id = '123'(user_id是INT)会让索引失效 - 联合索引必须满足最左前缀:
INDEX(a, b, c)无法用于WHERE b = 10,哪怕b单独建过索引也白搭
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED 不生效的常见原因
会话级设置看似灵活,但容易被框架或连接池覆盖。很多 ORM(如 MyBatis、Spring JDBC)默认复用连接并重置隔离级别,导致你设了等于没设。
- 检查实际生效值:
SELECT @@transaction_isolation,不是看变量名,而是看返回值是否为READ-COMMITTED - 确认
binlog_format是ROW:SHOW VARIABLES LIKE 'binlog_format';STATEMENT模式下 RC 可能引发主从不一致,MySQL 有时会悄悄回退到 RR - 连接池(如 HikariCP)可能在获取连接后执行
SET SESSION tx_isolation = ...,把你之前设的覆盖掉
RC 下仍需警惕的锁升级场景
即使开了 RC,以下情况仍可能扩大锁范围:低基数字段索引被优化器放弃、OR 条件导致索引失效、二级索引更新引发聚簇索引加锁。
-
WHERE status IN ('pending', 'processing')中status只有 3 个值,MySQL 很可能放弃索引走全表扫描 -
UPDATE t SET x=1 WHERE a=1 OR b=2——OR容易让执行计划退化,建议拆成两个语句或用UNION ALL - 用二级索引更新时,InnoDB 需先通过二级索引定位,再回主键加锁,若并发高,可能因主键锁争用形成瓶颈
真正降低锁冲突的关键不在隔离级别本身,而在每次 UPDATE / DELETE 是否精准命中索引行。RC 只是把“锁不住的范围”砍掉了,但“锁不住的行”还得靠索引和执行计划来兜底。











