答案:mysql加锁规则受存储引擎、隔离级别和SQL类型影响,InnoDB通过S锁、X锁、意向锁、记录锁、间隙锁和临键锁实现并发控制;加锁基于索引,不同隔离级别下加锁行为不同,RC级别不加间隙锁,RR级别使用临键锁防止幻读,Serializable下select自动加S锁;SELECT默认快照读不加锁,for UPDATE加X锁,LOCK IN SHARE MODE加S锁,UPDATE/delete对目标记录加X锁,INSERT加X锁并可能加间隙锁;死锁由InnoDB自动检测并回滚,建议按顺序访问资源以减少死锁。

MySQL的加锁规则主要依赖于存储引擎、事务隔离级别以及具体的sql语句类型。InnoDB是MySQL默认的事务型存储引擎,其加锁机制最为复杂也最常用。下面从几个关键角度说明InnoDB的加锁规则。
1. 锁的类型
InnoDB支持多种锁,常见的包括:
- 共享锁(S锁):允许多个事务读取同一行数据,但阻止写操作。
- 排他锁(X锁):阻止其他事务对已锁定的数据加任何类型的锁,用于写操作。
- 意向锁(Intention Locks):表级锁,表示事务打算在某行上加S锁或X锁。例如,IX锁表示要加X锁,IS表示要加S锁。
- 记录锁(Record Lock):锁住索引中的一条记录。
- 间隙锁(Gap Lock):锁住索引记录之间的“间隙”,防止幻读。
- 临键锁(Next-Key Lock):记录锁 + 间隙锁,锁住记录本身和前面的间隙,用于防止幻读。
2. 加锁与索引的关系
InnoDB的加锁是基于索引的,不是基于记录本身:
- 如果查询条件使用了主键或唯一索引,InnoDB通常只加记录锁。
- 如果查询条件使用的是非唯一索引,InnoDB会加临键锁(Next-Key Lock),即锁住当前记录和前面的间隙。
- 如果没有使用索引,InnoDB可能对所有行进行扫描并加锁,等价于全表扫描加锁,性能差且容易死锁。
3. 事务隔离级别的影响
不同的隔离级别会影响加锁行为:
- 读未提交(Read Uncommitted):不加间隙锁,可能出现脏读,但加锁最少。
- 读已提交(Read Committed):只加记录锁,不加间隙锁。MVCC版本控制用于一致性读,但可能存在不可重复读。
- 可重复读(Repeatable Read):InnoDB默认级别。使用临键锁防止幻读,保证可重复读。
- 串行化(Serializable):所有SELECT语句自动转为加共享锁的SELECT … LOCK IN SHARE MODE,避免并发问题。
4. 常见SQL语句的加锁情况
- SELECT … FROM …:默认使用MVCC,不加锁(快照读)。但在Serializable级别或显式加锁时会加S锁。
- SELECT … FOR UPDATE:加X锁,阻塞其他事务的读和写(当前读)。
- SELECT … LOCK IN SHARE MODE:加S锁,允许其他事务读但不能修改。
- UPDATE / DELETE:对符合条件的记录加X锁。
- INSERT:插入时会对新记录加X锁,并可能检查唯一性时加间隙锁。
5. 死锁与锁等待
InnoDB能自动检测死锁并回滚代价较小的事务。常见死锁场景包括:
- 多个事务以不同顺序访问多个表或记录。
- 间隙锁和记录锁交叉等待。
建议应用层按固定顺序操作资源,减少死锁概率。
基本上就这些。理解MySQL加锁规则的关键是掌握索引、隔离级别和锁类型的交互关系。实际开发中应尽量使用索引、避免长事务,并合理选择隔离级别。


