内容简介:InnoDB 支持需要强调一下,意向锁是一种即:
InnoDB 支持 多粒度锁(multiple granularity locking)
,它允许 行级锁
与 表级锁
共存,而 意向锁
就是其中的一种 表锁
。
意向锁(Intention Locks)
需要强调一下,意向锁是一种 不与行级锁冲突表级锁
,这一点非常重要。意向锁分为两种:
-
意向共享锁
(intention shared lock, IS):事务有意向对表中的某些行加 共享锁
(S锁)
-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。 SELECT column FROM table ... LOCK IN SHARE MODE; 复制代码
-
意向排他锁
(intention exclusive lock, IX):事务有意向对表中的某些行加 排他锁
(X锁)
-- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。 SELECT column FROM table ... FOR UPDATE; 复制代码
即: 意向锁是有数据引擎自己维护的,用户无法手动操作意向锁
,在为数据行加共享 / 排他锁之前,InooDB 会先获取该数据行所在在数据表的对应意向锁。
意向锁要解决的问题
我们先来看一下百度百科上对意向锁存在意义的描述:
如果另一个任务试图在该表级别上应用共享或排它锁,则受到由第一个任务控制的表级别意向锁的阻塞。第二个任务在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁。
设想这样一张 users
表:
id | name |
---|---|
1 | ROADHOG |
2 | Reinhardt |
3 | Tracer |
4 | Genji |
5 | Hanzo |
6 | Mccree |
事务 A 获取了某一行的排他锁,并未提交:
SELECT * FROM users WHERE id = 6 FOR UPDATE; 复制代码
事务 B 想要获取 users
表的表锁:
LOCK TABLES users READ; 复制代码
因为共享锁与排他锁 互斥
,所以事务 B 在视图对 users
表加共享锁的时候,必须保证:
- 当前没有其他事务持有 users 表的排他锁。
- 当前没有其他事务持有 users 表中任意一行的排他锁 。
为了检测是否满足第二个条件,事务 B 必须在确保 users
表不存在任何排他锁的前提下,去检测表中的每一行是否存在排他锁。很明显这是一个效率很差的做法,但是有了 意向锁
之后,情况就不一样了:
意向锁的兼容互斥性
意向锁是怎么解决这个问题的呢?首先,我们需要知道意向锁之间的兼容互斥性:
意向共享锁(IS) | 意向排他锁(IX) | |
---|---|---|
意向共享锁(IS) | 兼容 | 兼容 |
意向排他锁(IX) | 兼容 | 兼容 |
即 意向锁之间是互相兼容的 ,emmm......那你存在的意义是啥?
虽然意向锁和自家兄弟互相兼容,但是它会与普通的 排他 / 共享锁 互斥:
意向共享锁(IS) | 意向排他锁(IX) | |
---|---|---|
共享锁(S) | 兼容 | 互斥 |
排他锁(X) | 互斥 | 互斥 |
注意:这里的排他 / 共享锁指的都是表锁!!!意向锁不会与行级的共享 / 排他锁互斥!!!
现在我们回到刚才 users
表的例子:
事务 A
获取了某一行的排他锁,并未提交:
SELECT * FROM users WHERE id = 6 FOR UPDATE; 复制代码
此时 users
表存在两把锁: users
表上的 意向排他锁
与 id 为 6 的数据行上的 排他锁
。
事务 B 想要获取 users 表的共享锁:
LOCK TABLES users READ; 复制代码
此时 事务 B
检测事务 A 持有 users
表的 意向排他锁
,就可以得知 事务 A
必然持有该表中某些数据行的 排他锁
,那么 事务 B
对 users
表的加锁请求就会被排斥(阻塞),而无需去检测表中的每一行数据是否存在排他锁。
意向锁的并发性
这就牵扯到我前面多次强调的一件事情:
意向锁不会与行级的共享 / 排他锁互斥!!!
意向锁不会与行级的共享 / 排他锁互斥!!!
意向锁不会与行级的共享 / 排他锁互斥!!!
重要的话要加粗说三遍,正因为如此,意向锁并不会影响到多个事务对不同数据行加排他锁时的并发性(不然我们直接用普通的表锁就行了)。
最后我们扩展一下上面 users 表的例子来概括一下意向锁的作用(一条数据从被锁定到被释放的过程中,可能存在多种不同锁,但是这里我们只着重表现意向锁):
id | name |
---|---|
1 | ROADHOG |
2 | Reinhardt |
3 | Tracer |
4 | Genji |
5 | Hanzo |
6 | Mccree |
事务 A
先获取了某一行的 排他锁
,并未提交:
SELECT * FROM users WHERE id = 6 FOR UPDATE; 复制代码
-
事务 A
获取了users
表上的 意向排他锁 。 -
事务 A
获取了 id 为 6 的数据行上的 排他锁 。
之后 事务 B
想要获取 users
表的 共享锁
:
LOCK TABLES users READ; 复制代码
-
事务 B
检测到事务 A
持有users
表的 意向排他锁 。 -
事务 B
对users
表的加锁请求被阻塞(排斥)。
最后 事务 C
也想获取 users
表中某一行的 排他锁
:
SELECT * FROM users WHERE id = 5 FOR UPDATE; 复制代码
-
事务 C
申请users
表的 意向排他锁 。 -
事务 C
检测到事务 A
持有users
表的 意向排他锁 。 -
因为意向锁之间并不互斥,所以
事务 C
获取到了users
表的 意向排他锁 。 -
因为id 为 5 的数据行上不存在任何 排他锁
,最终
事务 C
成功获取到了该数据行上的 排他锁 。
以上所述就是小编给大家介绍的《详解 MySql InnoDB 中意向锁的作用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- InnoDB 并发插入,居然使用意向锁?
- 佛罗里达州一城市同意向黑客支付60万美元赎金 以恢复电脑记录
- Flutter 完整开发实战详解(十六、详解自定义布局实战)
- 数据结构 1 线性表详解 链表、 栈 、 队列 结合JAVA 详解
- 详解Openstack环境准备
- Java泛型详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。