锁的类型:
基于锁的属性分类 : 共享锁、排他锁。
基于锁的粒度分类: 行级锁(innodb)、表级锁(innodb、myisam)、页级锁(bdb 引擎)、记录锁、间隙锁、临键锁。
基于锁的状态分类:意向共享锁、意向排他锁。
- 共享锁(share lock)
共享锁又称读锁,当一个事务为数据加上读锁之后,其事务职能对该数据加读锁(可以加多个读锁,不能加写锁),而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加写锁,共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。
- 排他锁(exclusive lock)
排他锁又称写锁,当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁(只能加一把),直到改锁释放之后,其他事务才能对数据加锁,排他锁的目的数据修改时候,不允许其他人同时修改,也不允许其他人读取,避免出现脏数据和脏读的情况。
- 表锁:
表锁是指上锁的时候锁住的是整张表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能对表进行访问。
特点:粒度大,加锁简单,容易冲突;
- 行锁:
行锁是指上锁的时候锁住的是表的某一行记录,其他事物访问同一张表时,只有被锁住的记录不能访问,其他的记录正常访问。
特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高。
- 记录锁(record lock):
记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录。
精准条件命中,并且命中的条件字段是唯一索引
加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事物读取的脏读问题。
- 页锁:
页锁是mysql 中锁定粒度介于行级锁和表级锁中间的一种锁,表级锁速度快,行级锁冲突少,但速度慢,所以获取了折中的页级。一次锁定相邻的一组记录。
特点:开销和加锁时间介于表锁和行锁之间;会出现死锁,锁定粒度介于表锁和行锁止键,并发度一般。 - 间隙锁(GAP LOCK):
属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的一个区间,当表的相邻id 之间出现空隙则会形成一个区间,遵循左开右闭原则。
范围查询并且查询未命中纪录,查询条件必须命中索引,间隙锁只会出现在 repeatable_read (重复读) 的事务级别中。 触发条件:
防止幻读问题,事物并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一个事务中,a事务的两次查询的结果完全不一样。 比如表里面的数据id 为 1,4,5,7,10,那么会形成以下几个间隙区间,-n-1 区间,1 - 4 区间,7- 10 区间,10 - n 区间 (-n
代表无穷大,n代表正无穷大)
- 临建锁(next-keyLock):
也属于行锁的一种,并且它是 innodb 的行级默认算法,总结来说
他就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的多有间隙空间锁住,也会把相邻的一个区间也会锁住
触发条件,范围查询并命中,查询命中了索引。
结合记录锁和间隙锁的特性,临建锁避免了在范围查询时出现藏独、重复读、幻读问题,加了临界锁之后,在范围区内数据不允许被修改和插入。
如果当事务a 加锁之后就设置一个状态告诉后面的人,已经有人对里面的行加了一个排他锁,你们不能对整个表加加共享锁 或排他锁了,那么后面需要对整个表加锁的人只需要获取这个状态就知道自己是不是可以对表加锁,避免了对整个索引树的每个节点扫描是否加锁,而这个锁就是意向锁。
意向共享锁:
当一个事务试图对整个表进行共享锁之前,首先需要获得这个表的意向共享锁。
意向排他锁:
当一个事物时图对整个表进行加锁之前,首先需要获得这个表的意向排他锁。