锁的种类一般分为乐观锁和悲观锁两种。InnerDB引擎中锁使用的就是悲观锁,而按照锁的粒度划分可以分为行锁和表锁。为了支持多粒度锁定,InnoDB存储引擎引入了意向锁(Intention Lock),意向锁是一种表级锁。
锁的算法
锁是如何添加到对应的数据行上的,下面将接受三种锁的算法:Record Lock,Gap Lock和Next-Key Lock。
Record Lock 记录锁是存储引擎中最常见的锁,是加到索引记录的锁。
Gap Lock InnoDB 中还存在间隙锁(Gap Lock),间隙锁是对索引记录中一段连续区域的锁(一般针对非唯一索引而言)。
当使用 select * from user where id between 10 and 20 for update 的SQL时候,就会阻止其它事务像表中插入id=15的记录,因此整个范围都被间隙锁锁定了。
Next-Key Lock Next-Key 锁比其他两种就要复杂,它是记录锁和记录之前间隙锁的结合。在user表中有如下记录:
id | last_name | first_name | age |
|------|-------------|--------------|-------|
| 4 | stark | tony | 21 |
| 1 | tom | hiddleston | 30 |
| 3 | morgan | freeman | 40 |
| 5 | jeff | dean | 50 |
| 2 | donald | trump | 80 |
+------|-------------|--------------|-------
如果使用next-key锁,那么可以在需要的时候锁定如下范围(-∞, 21],(21, 30],(30, 40],(40, 50],(50, 80],(80, ∞) .Next-Key锁定的是当前值和前面范围的值。
当我们要更新一条记录,比如select t.* from user where age=30 for update; InnoDB不仅会在(21,30]加上 next-key锁,也会在(30,40]加上间隙锁,所以插入(21.40]范围内的记录都会被锁定。 Next-Key的作用是为了解决幻读的问题。
锁的选择:
1.如果更新条件没有走索引,此时会进行全表扫描,扫表的时候要阻止其他任何的更新操作,所以上升为表锁。
2.如果更新字段为索引字段,但非唯一索引(包含主键索引)。那么此时更新适合使用Next-Key Lock。
a.首选要在符合条件的记录上加排他锁,会锁定当前非唯一索引和对于主键索引的值。
b.还要保证锁定的区间不能插入新的记录
3.如果更新条件为唯一索引,则直接使用Record Lock。根据唯一索引找到记录。将主键索引值和唯一索引值加上Record Lock.