一、mysql中锁的分类
二、mysql中锁的按粒度分类
MySQL中的锁,按照锁的粒度分,分为以下三类:
1、全局锁:锁定数据库实例中的所有库、所有表。只能DQL不能DML,该锁用于数据库备份。
2、表级锁:每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低
3、行级锁:每次DML操作锁住对应的行数据 。行锁 锁定粒度小,发生锁冲突的概率最低,并发度高。
InnoDB的数据是基于索引组织的,行级锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁,锁住了索引项相当于锁住了行数据;
三、行级锁详细说明
3.1 行级锁分类–按锁定对象分
InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的
锁。对于行级锁,主要分为以下三类 :
1、记录锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。
2、间隙锁(Gap Lock):在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。间隙锁能确保索引记录间隙不变,防止其他事务在这个间隙进行insert,从而避免产生幻读。
注意:间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。
3、临键锁(Next-Key Lock):锁住数据,并同时锁住数据之间的间隙。
注意点:
1、InnoDB使用哪种行级锁,是与事务隔离级别相关的
(1)RU和RC隔离级别:只会使用记录锁,不存在间隙锁;
(2)RR和Serializable隔离级别:会存在记录锁、间隙锁和临键锁;
3.2 行级锁的分类–按共享性分
InnoDB实现了以下两种类型的行级锁:
1、共享锁(S):假设事务T1对数据加上共享锁,那么其他事务可以获得该数据的共享锁,但是不能获得该部分数据的排他锁读该部分数据,但不能修改。(T1不受影响,仍能获得任何锁)
2、排他锁(X):也叫排独占锁。假设事务T1对数据加上排他锁,那么其他事务既不能获得该数据的共享锁读、也不能获得该部分数据的排他锁。(T1不受影响,仍能获得任何锁)
共享锁、排他锁都是悲观锁
3.3 常用SQL语句使用锁的共享性
注意点:
1、SELECT…FROM语句不加任何悲观锁,也不会遵循悲观锁机制,他会忽略加在记录、间隙上的锁;
2、INSERT、UPDATE、DELETE是隐式加锁,即自动加锁;
3、SELECT … FOR UPDATE 和 SELECT … LOCK IN SHARE MODE是显示加锁;
4、显示加锁、隐式加锁的解锁时机为:事务提交,或事务回滚,或kill进程;
5、DDL 语句(如 ALTER、CREATE 等)加表级锁,且这些语句为隐式提交,不能回滚;
3.4 锁使用举例
案例1
案例2
使用锁,并发情况下就可能出现死锁。防止死锁的方法常有2种:
1、获取锁时,设置最长等待时间;
2、使用死锁检测算法,当检测到死锁时,回滚相关事务;(死锁检测的思路是:看有没有形成申请锁的圆环)
从上面案例可以看出:InnoDB防止死锁采用的是获取锁等待超时
案例3
事务1从S锁升级到X锁(不能从X锁降到S锁)
查看锁信息
可以通过“show engine innodb status”命令查看加锁信息。
注意:如果没有任何冲突,“show engine innodb status”命令看不到锁信息
也可以通过通过information_shcema.innodb_locks 表跟踪结果,当有锁等待时,该表产生数据
四、行级锁总结(重要)
1、"SELELCT…FROM"语句
-
使用的是MVCC乐观锁,与悲观锁机制无关,他不遵循悲观锁机制,会忽略加在记录上的任何锁。
-
但在读写串行化级别会在搜索遇到的索引记录上设置共享的next-key锁。如果where条件中使用唯一索引且命中数据,则仅设置一个记录锁(如果where条件中使用唯一索引且命中数据,仅会加一个间隙锁)。
2、RU、RC隔离级别不会存在间隙锁、Next-key 锁,只有记录锁;(RR/读写串行化与RC的区别,就是多了间隙锁。)
3、RR、读写串行化隔离级别才会存在间隙锁,会在扫描过的间隙都加间隙锁:
- 如果有二级索引,仅在二级索引扫描过的间隙加间隙锁,聚簇索引只加记录锁;
- 如果有索引且进行等值查询时,如果未命中数据,则仅会有一个间隙锁:因为索引是递增有序排列的,仍然符合会在扫描过的行上都加间隙锁条件。
- 如果where条件中使用唯一索引且进行等值查询时,如果命中数据, 则仅会有记录锁。
五、插入意向锁
mysql 为了提高数据插入的并发能力,新增了另一种行级锁–插入意向锁。
大致原理是:执行INSERT语句时,先判断是否有和插入意向锁冲突的锁,如果有,加插入意向锁,进入锁等待;如果没有,直接写数据,不加任何锁。
参考:
1、官网:https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html
2、https://www.aneasystone.com/archives/2017/12/solving-dead-locks-three.html
3、https://www.aneasystone.com/archives/2018/06/insert-locks-via-mysql-source-code.html
六、表锁
对于表级锁,主要分为以下三类:
-
表锁
-
元数据锁(meta data lock,MDL)
元数据可以理解为表结构,MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。
-
表级意向锁