
下面按MySQL InnoDB语境解释排他锁X 锁Exclusive Lock 共享锁S 锁Shared Lock 意向锁Intention Lock包括 IS 锁和 IX 锁它们的核心关系是共享锁我想读别人也可以读但别人不能改 排他锁我要改别人不能读锁定读也不能改 意向锁我准备在表里的某些行上加锁先在表级别打个标记1. 共享锁 S 锁共享锁也叫读锁。如果一个事务给某行加了共享锁其他事务仍然可以对这行加共享锁但不能加排他锁。例如SELECT * FROM users WHERE id 1 LOCK IN SHARE MODE;或者 MySQL 8 中也可以写SELECT * FROM users WHERE id 1 FOR SHARE;含义是我要读 id 1 这行并且不希望别人修改它。假设事务 A 执行BEGIN; SELECT * FROM users WHERE id 1 FOR SHARE;此时事务 B 也可以读SELECT * FROM users WHERE id 1 FOR SHARE;因为共享锁和共享锁兼容。但是事务 B 如果想改UPDATE users SET age 20 WHERE id 1;就会被阻塞。因为UPDATE需要对这行加排他锁而排他锁和共享锁冲突。2. 排他锁 X 锁排他锁也叫写锁。如果一个事务给某行加了排他锁其他事务不能再对这行加共享锁也不能加排他锁。常见语句UPDATE users SET age 20 WHERE id 1;或者DELETE FROM users WHERE id 1;或者SELECT * FROM users WHERE id 1 FOR UPDATE;这些都会对相关记录加排他锁。例如事务 ABEGIN; UPDATE users SET age 20 WHERE id 1;此时事务 B 执行UPDATE users SET age 30 WHERE id 1;会被阻塞。事务 B 执行SELECT * FROM users WHERE id 1 FOR SHARE;也会被阻塞。因为排他锁和其他锁都冲突。但是普通快照读SELECT * FROM users WHERE id 1;通常不会被阻塞因为普通SELECT走 MVCC不加行锁。S 锁和 X 锁兼容关系当前已有锁另一个事务申请 S 锁另一个事务申请 X 锁S 锁兼容冲突X 锁冲突冲突简单记读读可以并发 读写互斥 写写互斥4. 意向锁是什么意向锁是 InnoDB 的表级锁。它不是直接锁某一行而是在表级别声明我接下来要在这张表的某些行上加共享锁或排他锁。意向锁主要有两种IS 锁Intention Shared Lock意向共享锁 IX 锁Intention Exclusive Lock意向排他锁4.1 IS 锁事务想给某些行加共享锁之前会先给表加 IS 锁。例如SELECT * FROM users WHERE id 1 FOR SHARE;大致加锁过程1. 先给 users 表加 IS 锁 2. 再给 id 1 这行加 S 锁IS 锁的意思是我准备在这张表的某些行上加共享锁。4.2 IX 锁事务想给某些行加排他锁之前会先给表加 IX 锁。例如UPDATE users SET age 20 WHERE id 1;大致加锁过程1. 先给 users 表加 IX 锁 2. 再给 id 1 这行加 X 锁IX 锁的意思是我准备在这张表的某些行上加排他锁。5. 为什么需要意向锁主要是为了提高判断锁冲突的效率。假设事务 A 已经锁了users表里的某几行id 1 id 5 id 9现在事务 B 想执行LOCK TABLES users WRITE;也就是想给整张表加写锁。如果没有意向锁MySQL 可能需要检查这张表里每一行有没有被锁。有了意向锁后事务 A 在加行锁之前已经先在表上加了 IX 锁。事务 B 想加表级写锁时只要发现表上有 IX 锁就知道这张表里已经有人准备或正在加行级排他锁。于是可以直接判断冲突不需要逐行扫描。所以意向锁的核心作用是协调表锁和行锁之间的关系。6. 意向锁会不会阻塞普通行锁通常不会。例如事务 ABEGIN; UPDATE users SET age 20 WHERE id 1;事务 A 会持有users 表上的 IX 锁 id 1 行上的 X 锁事务 BBEGIN; UPDATE users SET age 30 WHERE id 2;事务 B 也需要users 表上的 IX 锁 id 2 行上的 X 锁这两个事务的 IX 锁是兼容的而且锁的是不同行所以通常可以并发执行。这说明意向锁不是为了阻塞普通行级操作 而是为了和表级锁做冲突判断。三者放在一起理解假设执行UPDATE users SET age 20 WHERE id 1;InnoDB 大致会1. 给 users 表加 IX 锁 2. 根据索引找到 id 1 这一行 3. 给 id 1 的索引记录加 X 锁 4. 执行更新 5. 事务提交或回滚后释放锁假设执行SELECT * FROM users WHERE id 1 FOR SHARE;InnoDB 大致会1. 给 users 表加 IS 锁 2. 根据索引找到 id 1 这一行 3. 给 id 1 的索引记录加 S 锁 4. 返回数据 5. 事务提交或回滚后释放锁