行级锁与表级锁的冲突

InnoDB除了给行加行级别锁,也可以加表级别锁。

事务A获取了teachers表id=1行的行排它锁

1
2
3
4
5
6
7
mysql> select * from teachers where id = 1 for update;
+--------+-----+-----+
| id | name | age |
+--------+-----+-----+
| 1 | 张三 | 60 |
+--------+-----+-----+
1 row in set (0.01 sec)

在事务A未提交时,事务B想获取表teachers的表共享锁

1
mysql> lock tables teachers read;

如果事务B成功获取到teachers表共享锁,就意味能够读取表中任意一行数据,但这明显与事务A中加了排他锁的那行有冲突,所以从理论上此时就不能让事务B获取到表共享锁。

但是它们一个是表级别锁一个是行级别锁,两种不同的东西,无法直接锁兼容性比较,那就走比较笨的方式,扫描表中所有的行来判断是否有排他锁的行,最后再决定是否给事务B提供表共享锁。

这样效率太低下,如果能直接2个表级锁比较就高效率了,意向锁就应运而生。

意向锁

意向锁是一种表级别锁,并且是MySQL内置已实现的、自动开启且无法关闭的机制。

在上述的例子中,事务A获取到行排他锁之前,会获取一个teaches表的意向排他锁,事务B想获取teachers表的表共享锁,就直接与意向排他锁进行比较,这样就是同级别的比较,遵循简单的规则,立马得到锁兼容性结果。

意向锁有两种:意向共享锁和意向排他锁。

意向共享锁(IS)

事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

意向排它锁(IX)

事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

锁兼容性

意向锁表级锁兼容性表。

S:表级共享锁

X:表级排它锁

IS:意向共享锁

IX:意向排它锁

IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容