1.概述
InnoDB支持多粒度锁定,允许行锁和表锁共存。意向锁是在表级别上设置的锁,预示着事务稍后可能会在表中的某行上设置哪种类型的锁(共享锁 or 排他锁)。
意向锁有两种主要类型:
- 意向共享锁(Intention Shared Lock,简称 IS):表明一个事务打算对表中的某一行设置共享锁。
- 意向排它锁(Intention Exclusive Lock,简称 IX) :表明一个事务打算对表中的某一行设置排他锁。
例如,对表中的一个数据行执行 SELECT ... FOR SHARE
语句,会设置一个 IS 锁。执行 SELECT ... FOR UPDATE
会设置一个 IX 锁。下面是锁兼容性的矩阵:
X | IX | S | IS | |
---|---|---|---|---|
X | Conflict | Conflict | Conflict | Conflict |
IX | Conflict | Compatible | Conflict | Compatible |
S | Conflict | Conflict | Compatible | Compatible |
IS | Conflict | Compatible | Compatible | Compatible |
意向锁并不会阻止任何全表请求(例如,LOCK TABLES … WRITE)。意向锁的主要目的是显示有人正在锁定一行,或者准备锁定一行。在"SHOW ENGINE INNODB STATUS"的输出中,意向锁的事务数据可能看起来像这样:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
实际上,如果不使用意向锁,要确定表级锁和行级锁之间的冲突,可能需要遍历所有行的行锁。有了意向锁,我们只需要检查是否存在意向锁,就可以确定是否存在行锁。
2.实验部分
首先,我们创建测试表 sys_user
:
CREATE TABLE `sys_user` (
`id` int NOT NULL,
`name_pinyin` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
2.1 冲突实验
然后,我们进行以下操作来测试锁的冲突:
第一步,事务A获取IS锁,代码如下:
# Transaction A
BEGIN;
SELECT * FROM sys_user WHERE id = 17 lock in share mode;
第二步,事务B尝试获取IX锁,代码如下:
# Transaction B
BEGIN;
SELECT * FROM sys_user WHERE id = 17 FOR UPDATE;
执行以上两步,你会发现事务B阻塞,这是因为IX锁与IS锁冲突。
2.2 兼容测试
接下来,我们测试一些兼容的锁类型。
第一步,事务A获取IS锁,代码如下:
# Transaction A
BEGIN;
SELECT * FROM sys_user WHERE id = 17 lock in share mode;
第二步,事务B尝试获取S锁,代码如下:
# Transaction B
BEGIN;
SELECT * FROM sys_user WHERE id = 17 lock in share mode;
执行以上两步,你会发现事务B没有阻塞,这是因为S锁与IS锁兼容。这个实验让你明白了InnoDB的意向锁能预防死锁发生,确保数据库操作的顺利进行。
2.3 锁结果查询截图
3. 总结
本文深入探讨了InnoDB数据库的意向锁概念,包含意向共享锁和意向排他锁两种,它们在表级别上显示了事务是否正在锁定一行或即将锁定一行。在我们执行 SELECT…FOR SHARE或SELECT…FOR UPDATE语句时,会分别设置 IS和IX锁。
我们也查看了如何在 "SHOW ENGINE INNODB STATUS" 输出中获取意向锁的事务数据。在检查冲突的时候,如果不使用意向锁,我们可能需要遍历所有行的行锁。而有了意向锁,我们只需检查是否存在意向锁,就可以确定是否有行锁。
此外,我们也通过实验的方式,展示了如何在 MySQL 中观察和理解锁的冲突,以及如何测试兼容的锁类型。这对于理解MySQL的锁机制,预防潜在的死锁以及提高数据库操作的顺畅性非常有帮助。
希望能在面试中帮到你。