共享/排它锁(Shared and Exclusive Locks)
按照兼容性来分类,InnoDB有共享锁和排它锁两种行级锁。
- 共享锁(S):又称读锁。允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
- 排他锁(X):又称写锁。允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。
简单来说就是,如果一个事务上了共享锁,那么不管哪个事务都不可以对改数据进行修改。但是,其他事务,仍然可以对改数据加共享锁。排他锁则是当一个事务上了排他锁,那么其他事务不可以在对该数据进行上锁,直到该事务释放锁。
意向锁(Intention Locks)
InnoDB为了支持多粒度锁机制(multiple granularity locking),即允许行级锁与表级锁共存,而引入了意向锁(intention locks)。意向锁是指,未来的某个时刻,事务可能要加共享/排它锁了,先提前声明一个意向。
意向锁是一个表级别的锁(table-level locking);
意向锁又分为:
- 意向共享锁(intention shared lock, IS),它预示着,事务有意向对表中的某些行加共享S锁;
- 意向排它锁(intention exclusive lock, IX),它预示着,事务有意向对表中的某些行加排它X锁;
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据的索引项加锁;
临键锁(Next-key Locks)
通过临键锁可以解决幻读的问题。 当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。
间隙锁(Gap Locks)
对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
使用间隙锁,会对叶子节点的两端进行加锁
- 间隙锁的目的是为了防止幻读,以满足相关隔离级别的要求
记录锁(Record Locks)
顾名思义,记录锁就是为某行记录加锁,它封锁该行的索引记录:
插入意向锁(Insert Intention Locks)
对已有数据行的修改与删除,必须加强互斥锁(X锁),那么对于数据的插入,是否还需要加这么强的锁,来实施互斥呢?插入意向锁,孕育而生。
插入意向锁,是间隙锁(Gap Locks)的一种(所以,也是实施在索引上的),它是专门针对insert操作的。多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
自增锁(Auto-inc Locks)
自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
总结
以上总结的7种锁,可以按两种方式来区分:
-
按锁的兼容性来划分,可以分为共享、排他锁;
共享锁(S锁、IS锁),可以提高读读并发;
为了保证数据强一致,InnoDB使用强互斥锁(X锁、IX锁),保证同一行记录修改与删除的串行性;
-
按锁的粒度来划分,可以分为:
表锁:意向锁(IS锁、IX锁)、自增锁;
行锁:记录锁、间隙锁、临键锁、插入意向锁;
其中,InnoDB的细粒度锁(即行锁),是实现在索引记录上的(如果未命中索引则会失效);
记录锁锁定索引记录;间隙锁锁定间隔,防止间隔中被其他事务插入;临键锁锁定索引记录+间隔,防止幻读;
InnoDB使用插入意向锁,可以提高插入并发;
间隙锁(gap lock)与临键锁(next-key lock)只在Repeatable-Read(RR可重复读)以上的级别生效,Read-Committed(RC读已提交)下会失效。