Innodb锁的类型
- 共享/排它锁(Shared and Exclusive Locks)
- 意向锁(Intention Locks)
- 记录锁(Record Locks)
- 间隙锁(Gap Locks)
- 临键锁(Next-key Locks)
- 插入意向锁(Insert Intention Locks)
- 自增锁(Auto-inc Locks)
首先知道的一些点
select … for update 这代表加了X锁
select … lock in share mode 这代表加了S锁
共享/排它锁
这个就比较简单了,X锁(排他)和S锁(共享)
X | S | |
---|---|---|
X | 互斥 | 互斥 |
S | 互斥 | 兼容 |
意向锁
S | X | |
---|---|---|
IS | 兼容 | 互斥 |
IX | 互斥 | 互斥 |
意向锁分为:
- 排他意向锁 IX
- 共享意向锁 IS
IX IS互相兼容
在Innodb支持多粒度加锁,允许事务在行锁和表锁共同存在,在加锁时候,必须前往前面加锁
翻译过来就是这样的:
首先数据库的层次为
数据库
—表
—页
—记录
和一颗树一样,根节点是数据库,然后下面一层是表,再下一层是页,再下一层是记录
然后如果给记录加S锁,必须先给数据库,表,页都加IS锁
事务A | 事务B |
---|---|
记录2加S锁(意味着数据库,表,页均加IS锁) | |
表加X锁 |
理论上事务B加X锁,那么这个表中所有数据都不能修改,那么我总不能在这个表中一行一行的去看是否加了锁吧这时候意向锁的作用就出来了,因为事务B加表锁X,那么在表上事务B会看到事务A的IS锁,那么事务B阻塞,无需遍历整个表
记录锁
记录锁,它封锁索引记录,例如:
select * from table where id=1 for update;
它会在id=1的索引记录上加锁,以阻止其他事务插入,更新,删除id=1的这一行。
需要说明的是:
select * from table where id=1;
则是快照读,它并不加锁
间隙锁
这个封锁的区间,索引记录区间
假设表table
id,name,number
1,xx,2
2,yy,6
3,zz,8
select * from table where id between 1 and 10 for update
那么会阻塞其他事务在【1,10】区间内插入元组。
select * from table where number = 4 for update 这种情况下number不是唯一索引,在RR下使用间隙锁
封锁的区间是【2,6】
间隙的含义就是,记录之间的区间。
临键锁
临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
解释一下上面的话
临键锁会封锁索引记录本身,以及索引记录之前的区间。
还不懂???
假设表table(id,name,number)
1,x ,2
3,y,4
5,y,6
10,z,8
那么临键锁封锁的是number的话,区间是
【-无穷,2】
【2,4】
【4,6】
【6,8】
【8,+无穷】
select * from table where number = 4 for update 这个语句执行
封锁【2,4】【4,6】而且这个记录4本身也被锁定,而间隙锁只会锁定区间不锁定自己
插入意向锁
间隙锁的一种
多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
也就是说有个索引区间 比如【4,10】
插入元组6 8
本来是锁住整个区间的,但是这个插入意向锁,可以允许相同索引区间中元组不同行的并发执行,互不影响
自增锁
假设表
table(id,name) 其中id自增主键,默认事务隔离级别可重复读
事务A | 事务B |
---|---|
insert into table values(x) | |
insert into table values(y) | |
insert into table values(z) | |
select * from table |
假设id从1开始,假设事务B不会被阻塞
事务A插入了两条数据
1,x
3,z
事务B插入一条数据
2,y
在上一篇数据库隔离机制的实现讲解了可重复读的隔离机制下,是避免幻读的
在事务Aselect后,发现卧槽我特么插入了两条,怎么会没有2,产生了幻读
自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
你们以为结束了吗??,怎么可能Mysql中有个参数innodb_autoinc_lock_mode 默认是1,导致了并发insert不会产生表锁。不然并发插入岂不是大大影响效率
ps
所有的锁都得到特定的事务隔离机制中才能起作用,如果是读未提交的状态下,上面这些都是没用的