1.全局锁
//加全局锁 flush tables with read lock //释放全局锁 unlock tables
执行后,整个数据库就处于只读状态,加上了全局锁。全局锁颗粒度比表级锁大,此时所有线程对表结构、表数据只能执行读了。
当然,如果当前加全局锁的会话断开,全局锁会被自动释放。
全局锁主要用于全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新
而出现备份文件的数据与预期的不一样。
2.表级锁
2.1表锁
//表级别的共享锁,也就是读锁;
//允许当前会话读表,阻止其他会话写表。同时本会话不能访问其他表。
lock tables student read;//表级别的独占锁,也就是写锁;
//允许当前会话对表进行读写操作,阻止其他会话对表进行任何操作(读或写)。
lock tables student write;
2.2意向锁
当要使用表锁时,如何判断表中的记录没有行锁呢,一行一行遍历肯定是不行,性能太差。要用意向锁来快速判断是否可以对某个表使用表锁。
- 意向共享锁(Intention Shared Lock,IS 锁):事务有意向对表中的某些记录加共享锁(S 锁),加共享锁前必须先取得该表的 IS 锁。
- 意向排他锁(Intention Exclusive Lock,IX 锁):事务有意向对表中的某些记录加排他锁(X 锁),加排他锁之前必须先取得该表的 IX 锁。
意向锁之间兼容,与行级的共享锁和排他锁兼容,但是和表级的共享锁和排他锁互斥。
所以说当执行增、删、改操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。另外当前读的select也会加共享锁、独占锁。
3.行锁
3.1间隙锁
间隙锁是一种加在两个索引之间的锁,锁的是一个开区间,只存在于可重复读隔离级别。
假设,表中有一个范围id为(3,5]的next-key lock,那么其他事务即不能插入id=4记录,也不能修改id=5这条记录。
临建锁和间隙锁在幻读中的使用场景
详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁) - HappyDeveloper - 博客园
使用间隙锁的情况
非唯一索引的等值查询:例如
SELECT * FROM table WHERE non_unique_col = 5 FOR UPDATE
,若5
存在,会锁定5
周围的间隙;若5
不存在,则锁定其应存在的间隙。范围查询:如
WHERE id > 10
,若未命中记录,会锁定符合条件的间隙。唯一索引的等值查询(未命中):如
SELECT * FROM table WHERE unique_col = 15 FOR UPDATE
,当15
不存在时,锁定其所在的间隙。临键锁触发条件
非唯一索引的范围查询:如
WHERE non_unique_col BETWEEN 5 AND 10
。唯一索引的范围查询:如
WHERE unique_col > 10
。默认锁机制:在可重复读级别下,InnoDB默认对索引扫描使用临键锁
3.2记录锁
记录锁是最简单的行锁,仅锁住一行,有读锁和写锁之分,读写锁互斥。
如:
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE
如果C1字段是主键或者是唯一索引的话,这个SQL会加一个记录锁,记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁。它会阻塞其他事务对这行记录的插入、更新、删除。
3.3临键锁
Next-key锁是记录锁和间隙锁的组合,解决了锁定读的幻读问题(非锁定读用快照读即可解决幻读),它指的是加在某条记录以及这条记录前面间隙上的锁。说得更具体一点就是:临键锁会封锁索引记录本身,以及索引记录之前的区间,即它的锁区间是左开右闭,比如 (
5,10]
。在 InnoDB 默认的隔离级别 可重复读 下,行锁默认使用的是临键锁。但是,如果操作的索引是唯一索引或主键,InnoDB 会对临键锁进行优化,将其降级为 记录锁 ,即仅锁住索引本身,而不是范围。
3.4自增锁(表级锁)
专门针对
AUTO_INCREMENT
类型的列,对于这种列,如果表中新增数据时就会去持有自增锁。简言之,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
3.5插入意向锁
假设事务 A 已经对表加了一个范围 id 为(3,5)间隙锁。
当事务A还没提交的时候,事务B向该表插入一条id=4的新记录,这时会判断到插入的位置已经被事务A加了间隙锁,于是事物B会生成一个插入意向锁,然后将锁的状态设置为等待状态(PS:MySQL加锁时,是先生成锁结构,然后设置锁的状态,如果锁状态是等待状态,并不是意味着事务成功获取到了锁,只有当锁状态为正常状态时,才代表事务成功获取到了唢,此时事务B就会发生阻塞,直到事务A提交了事务。
行级锁和表级锁对比
- 表级锁: MySQL 中锁定粒度最大的一种锁(全局锁除外),是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。不过,触发锁冲突的概率最高,高并发下效率极低。表级锁和存储引擎无关,MyISAM 和 InnoDB 引擎都支持表级锁。
- 行级锁: MySQL 中锁定粒度最小的一种锁,是 针对索引字段加的锁 ,只针对当前操作的行记录进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。行级锁和存储引擎有关,是在存储引擎层面实现的。
- InnoDB 的行锁是针对索引字段加的锁,表级锁是针对非索引字段加的锁。当我们执行
UPDATE
、DELETE
语句时,如果WHERE
条件中字段没有命中唯一索引或者索引失效的话,就会导致扫描全表对表中的所有行记录进行加锁。