MySQL锁机制
MySQL 锁机制
参考:
- https://www.xiaolincoding.com/mysql/lock/mysql_lock.html
可以分为:全局锁、表级锁、行级锁。
全局锁
加全局锁命令:flush tables with read lock
,执行后,整个数据库就处于只读状态了,这时其他线程执行读之外的操作都会被阻塞。
释放全局锁命令:
- 主动使用命令:
unlock tables
- 而如果加锁的这个会话断开了,全局锁会被自动释放。
应用场景:
- 全库的逻辑备份,在备份期间,不会因为数据 or 表结构的更新,而出现备份文件与预期不一致。
缺点:
- 因为是只读状态,因此会使得需要更改操作的业务暂时停滞。
数据库备份-不使用全局锁
使用全局锁进行数据库备份时,会使得更新等业务停滞。可以换一种思路:隔离级别-可重复读 + MVCC
。
这种方式:
-
隔离级别 - 可重复读:可以解决 脏读、不可重复读 问题。
-
MVCC(多版本并发控制)技术:在备份数据库之前会开启事务。在进行快照读时,会创建 Read View快照,然后整个事务执行期间都在用这个 Read View,因此被分期间业务依然可以对数据进行更新操作。
表级锁
MySQL 里面表级别的锁有这几种:
- 表锁;
- 元数据锁(MDL);
- 意向锁;
- AUTO-INC 锁;
表锁:共享表锁、独占表锁
表锁可以分为:
表读锁
:多个事务可以同时对一个表加读锁,互不影响。多个事务可以同时读取表中的数据,但不能对表进行写操作(插入、更新、删除)。表写锁
:当一个事务对表加上写锁时,其他事务既不能对该表进行读操作,也不能进行写操作。只有持有写锁的事务完成其操作并释放锁后,其他事务才能对该表进行操作。
lock tables 表名 read; -- 表级别的共享锁,读锁
lock tables 表名 write; -- 表级别的独占锁,写锁
元数据锁
参考:
- https://opensource.actionsky.com/20220426-mysql/
- https://www.xiaolincoding.com/mysql/lock/mysql_lock.html
元数据锁(metadata lock):是针对表结构的锁,也就是对表结构的读、更改 会加锁。它主要是为了保证并发环境下 表结构 和 表数据的一致性。
说明:不需要显示的使用 MDL,因为当我们对数据库表结构进行操作时,会自动给这个表加上 MDL:
- 对表数据进行CRUD操作时,会自动加一个 MDL 读锁。即此时,只能查看表结构,不允许修改。
- 对表结构变更操作时,会自动加一个 MDL 写锁。即当对表结构更改时,其他线程无法读取表结构、也无法对表数据进行CRUD操作。
意向锁:意向共享锁、意向独占锁
1、定义:意向锁是表级别的锁。意向锁用于优化锁的检查:
- 当事务试图对表的某个行加锁时,它首先需要在表级别上获得相应的意向锁。
- 如果其他事务已经持有与该意向锁冲突的表级锁,则当前事务将立即知道它无法在该行上获得锁,而无需检查表中每一行上的锁情况。这大大减少了锁检查的开销。
2、注意:
- 意向锁不是由用户请求的,而是由MySQL管理的。即,我们正常使用行级别锁时,MySQL会自动使用意向锁 优化锁的检查。
- 意向锁并不知直接锁定资源,而是为了通知其他事务,防止它们在资源上设置不兼容的锁;
3、使用:以下是设置行级别锁的语句,这里主要解释这些语句执行时MySQL会自动设置意向锁
-- MySQL会先在表级别上使用意向共享锁,然后才会对 要读取的行数据 尝试加 行级别的共享锁
select ... lock in share mode;-- MySQL会先在表级别上使用独占锁,然后才会对 要读取的行数据 尝试加 行级别的独占锁
select ... for update;
AUTO-INC 锁
AUTO-INC 锁 作用:在创建表时使用AUTO_INCREMENT
关键字声明主键,后续插入数据时数据库会自动为数据设置主键,这是通过AUTO-INC 锁实现的。
AUTO-INC 锁 释放:AUTO-INC 锁不是事务提交之后才释放,而是在执行完数据插入语句后就会立即释放。
问:AUTO-INC 锁 如何保证主键连续递增?
答:一个事务在持有 AUTO-INC 锁的过程中,其他事务的如果要向该表插入语句都会被阻塞,从而保证插入数据时,被 AUTO_INCREMENT
修饰的字段的值是连续递增的。
行级锁
InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。
行级别的锁有三种类型:(它们是对 索引 加锁)
Record Lock
,记录锁,也就是仅仅把一条记录锁上;Gap Lock
,间隙锁,锁定一个范围,但是不包含记录本身;Next-Key Lock
:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。
Record Lock
Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有 S(共享) 锁和 X(独占) 锁之分的。
Gap Lock
Gap Lock 称为间隙锁,只存在于可重复读隔离级别。它锁定一个范围,但不包括记录本身。在这个范围内,不允许插入新的数据。
间隙锁也存在 S锁、X锁。但是没什么区别:间隙锁之间是兼容的,两个事务可以同时包含共同间隙范围的间隙锁,不存在互斥关系。
Next-Key Lock
Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。它也是存在隔离级别为 可重复读 下。
- 如果一个事务获取了X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的。
问:Next-Key Lock 可以解决幻读吗?
答:可以,在可重复读隔离级别下,Next-Key Lock 通过锁定一个范围以及这个范围内的具体记录来防止其他事务插入新的记录,从而避免了幻读现象。
- 一个事务使用范围查询读取了一些记录,此时数据库会对这个查询范围加上 Next-Key Lock。其他事务如果尝试在这个范围内插入新记录,就会被阻塞(防止其他事务修改数据),直到持有 Next-Key Lock 的事务提交或回滚。
- 这样就保证了在同一个事务中,重复执行相同的范围查询时,不会出现新插入的记录,即解决了幻读问题。
插入意向锁
在 MySQL 的 InnoDB 存储引擎中,插入意向锁(Insert Intention Lock)是一种特殊类型的间隙锁。是行级别的锁。
作用:它不是真正的锁,而是一种标记,用于表明事务的插入意图。它可以与 间隙锁(如next-key lock)配合使用,从而提高并发性能。
例子:
- 当一个事务持有 Next-Key Lock 时,其他事务的插入操作可能会被阻塞,即使插入的位置不在已锁定的范围内。
- 而插入意向锁可以明确表示事务的插入意图,只有在插入位置冲突时才会阻塞,更加灵活地控制了插入操作的并发。如果另一个事务要在这个范围内插入数据,它会持有插入意向锁。插入意向锁会与 Next-Key Lock 进行协调,确保数据的一致性,同时尽可能地允许并发插入操作。