IS | IX | |
IS | 兼 容 | 兼 容 |
IX | 兼 容 | 兼 容 |
虽然意向锁之间互相兼容,但是它与共享锁/排它锁互斥,其兼容互斥表如下:
S | X | |
IS | 兼 容 | 互 斥 |
IX | 互 斥 | 互 斥 |
排它锁是很强的锁,不与其他类型的锁兼容。这其实很好理解,修改和删除某一行的时候,必须获得强锁,禁止这一行上的其他并发,以保障数据的一致性。
3. 记录锁(Record Locks)
记录锁,它封锁索引记录,例如(其中id为pk):
create table lock_example(id smallint(10),name varchar(20),primary key id)engine=innodb;
数据库隔离级别为RR,表中有如下数据:
10, zhangsan
20, lisi
30, wangwu
select * from t where id=1 for update;
其实这里是先获取该表的意向排他锁(IX),再获取这行记录的排他锁(我的理解是因为这里直接命中索引了),以阻止其他事务插入,更新,删除id=1的这一行。
4. 间隙锁(Gap Locks)
间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。依然是上面的例子,InnoDB,RR:
select * from lock_example where id between 8 and 15 for update;
这个SQL语句会封锁区间(8,15),以阻止其他事务插入id位于该区间的记录。
间隙锁的主要目的,就是为了防止其他事务在间隔中插入数据,以导致“不可重复读”。如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。
5. 临键锁(Next-key Locks)
临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
默认情况下,innodb使用next-key locks来锁定记录。但当查询的索引含有唯一属性的时候,Next-Key Lock 会进行优化,将其降级为Record Lock,即仅锁住索引本身,不是范围。
举个例子,依然是如上的表lock_example,但是id降级为普通索引(key),也就是说即使这里声明了要加锁(for update),而且命中的是索引,但是因为索引在这里没有UK约束,所以innodb会使用next-key locks,数据库隔离级别RR:
事务A执行如下语句,未提交:
select * from lock_example where id = 20 for update;
事务B开始,执行如下语句,会阻塞:
insert into lock_example values('zhang',15);
如上的例子,事务A执行查询语句之后,默认给id=20这条记录加上了next-key lock,所以事务B插入10(包括)到30(不包括)之间的记录都会阻塞。临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。
6. 插入意向锁(Insert Intention Locks)
对已有数据行的修改与删除,必须加强互斥锁(X锁),那么对于数据的插入,是否还需要加这么强的锁,来实施互斥呢?插入意向锁,孕育而生。
插入意向锁,是间隙锁(Gap Locks)的一种(所以,也是实施在索引上的),它是专门针对insert操作的。多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
Insert Intention Lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.
举个例子(表依然是如上的例子lock_example,数据依然是如上),事务A先执行,在10与20两条记录中插入了一行,还未提交:
insert into t values(11, xxx);
事务B后执行,也在10与20两条记录中插入了一行:
insert into t values(12, ooo);
因为是插入操作,虽然是插入同一个区间,但是插入的记录并不冲突,所以使用的是插入意向锁,此处A事务并不会阻塞B事务。
7. 自增锁(Auto-inc Locks)
自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns. In the simplest case, if one transaction is inserting values into the table, any other transactions must wait to do their own inserts into that table, so that rows inserted by the first transaction receive consecutive primary key values.
举个例子(表依然是如上的例子lock_example),但是id为AUTO_INCREMENT,数据库表中数据为:
1, zhangsan
2, lisi
3, wangwu
事务A先执行,还未提交: insert into t(name) values(xxx);
事务B后执行: insert into t(name) values(ooo);
此时事务B插入操作会阻塞,直到事务A提交。
总结
以上总结的7种锁,个人理解可以按两种方式来区分:
1. 按锁的互斥程度来划分,可以分为共享、排他锁;
2. 按锁的粒度来划分,可以分为:
其中
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。