目录
- 一、锁
- 1.1 什么是锁?
- 1.2 全局锁
- 1.2.1 定义
- 1.2.2 应用场景
- 1.2.3 会出现的问题
- 1.2.4 解决方法
- 1.3 表级锁
- 1.3.1 表锁
- 1.3.2 元数据锁(MDL)
- 1.3.3 意向锁
- 1.3.4 AUTO-INC锁
- 1.4 行级锁
- 1.4.1 记录锁(Record Lock)
- 1.4.2 间隙锁(Gap Lock)
- 1.4.3 Next-Key Lock(记录锁+间隙锁)
- 1.4.4 插入意向锁
一、锁
1.1 什么是锁?
**锁是用来控制对数据库中数据访问的机制。**在并发环境下,多个用户可能同时访问相同的数据,这样就会产生数据的冲突和不一致的情况,为了避免这种情况发生,MySQL提供了多种锁机制。
1.2 全局锁
1.2.1 定义
全局锁就是对整个数据库实例加锁。
MySQL提供了一个加全局读锁的方法,命令是:flush tables with read lock
,执行后,整个数据库就处于只读状态了。
1.2.2 应用场景
全库逻辑备份。
这样在备份数据库期间,不会因为数据或表结构的更新,而出现备份文件的数据与预期的不一样。
1.2.3 会出现的问题
加上全局锁,意味着整个数据库都是只读状态。
- 那么如果数据库里有很多数据,备份就会花费很多的时间,关键是备份期间,业务只能读数据,而不能更新数据,这样会造成业务停滞。
- 若从库备份,则在备份期间无法执行主库同步的binlog,则会导致主从延迟。
1.2.4 解决方法
前提:数据库的引擎支持的事务支持可重复读的隔离级别。例如Innodb,MyiSam不支持事务,所以只能全局锁。
mysqldump是官方的逻辑备份工具。当mysqldump使用参数-single-transaction时,将在导数据之前启动事务,由于MVCC
的支持,数据可以在这个过程中正常更新。single-transaction仅适用于所有表使用事务引擎的库。
1.3 表级锁
1.3.1 表锁
- 表共享读锁:
lock tables t_student read;//表级别的共享锁,也就是读锁;
读锁会阻塞写。 - 表独占写锁:
lock tables t_stuent write;//表级别的独占锁,也就是写锁;
写锁会阻塞写和读 。 - 释放锁:
unlock tables
;释放当前会话的所有表锁
1.3.2 元数据锁(MDL)
MDL不需要显式使用,数据库自动调用
对一张表进行 CRUD 操作时,加的是 MDL 读锁;
对一张表做结构变更操作的时候,加的是 MDL 写锁;
MDL 是为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。
当有线程在执行 select 语句( 加 MDL 读锁)的期间,如果有其他线程要更改该表的结构( 申请 MDL 写锁),那么将会被阻塞,直到执行完 select 语句( 释放 MDL 读锁)。
反之,当有线程对表结构进行变更( 加 MDL 写锁)的期间,如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁),那么就会被阻塞,直到表结构变更完成( 释放 MDL 写锁)。
注意:事务执行期间,MDL 是一直持有的。开启长事务的同时其他事务变更表字段(MDL写锁),长事务不及时提交,会导致之后的所有操作都被阻塞。
MDL写锁优先级大于MDL读锁
1.3.3 意向锁
在使用
InnoDB 引擎
的表里对某些记录加上「共享锁/独占锁
(行锁)」之前,需要先在表级别加上一个「意向共享锁/意向独占锁
」;
为什么会有意向锁?
表锁和行锁是满足读读共享、读写互斥、写写互斥的。
没有意向锁
:加「独占表锁」
时,就需要遍历表里所有记录,查看是否有记录存在独占行锁,这样效率会很慢。
有意向锁
:加「独占表锁」
时,直接查该表是否有意向独占锁。
所以,意向锁的目的是为了快速判断表里是否有记录被加锁
1.3.4 AUTO-INC锁
主键自增使用的就是AUTO-INC锁
在插入数据时,会加一个表级别的 AUTO-INC 锁
,然后为被 AUTO_INCREMENT 修饰的字段赋值递增的值,等插入语句执行完成后,才会把 AUTO-INC 锁释放掉。
AUTO-INC 锁是特殊的表锁机制,锁不是再一个事务提交后才释放,而是再执行完插入语句后就会立即释放。
但是, AUTO-INC 锁再对大量数据进行插入的时候,会影响插入性能,因为另一个事务中的插入会被阻塞。
轻量级的锁
:在插入数据时,给该字段赋值一个自增的值后,直接释放,不再等待整条语句执行完毕。
1.4 行级锁
InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。
共享锁(S锁)满足读读共享,读写互斥。独占锁(X锁)满足写写互斥、读写互斥。
1.4.1 记录锁(Record Lock)
只将当前数据加锁
S锁与X锁不兼容,X锁与X锁不兼容
1.4.2 间隙锁(Gap Lock)
锁定一个范围,但是不包含记录本身(左开右开区间)
只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。
间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的。
1.4.3 Next-Key Lock(记录锁+间隙锁)
锁定一个范围,并且锁定记录本身(左开右闭区间)
next-key lock 是包含间隙锁
+记录锁
的,如果一个事务获取了 X 型的 next-key lock
,那么另外一个事务在获取相同范围的 X 型的 next-key lock
时,是会被阻塞的(XX互斥)。
1.4.4 插入意向锁
一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(
next-key lock
也包含间隙锁)。
如果有的话,插入操作就会发生阻塞,在此期间会生成一个插入意向锁
插入意向锁名字虽然有意向锁,但是它并不是意向锁,它是一种特殊的间隙锁,属于行级别锁
。