mysql 加锁算法 详解
锁
锁分类
从锁的操作划分
- 共享锁和排他锁
- 共享锁(读锁)和排他锁(写锁)。
- 对于更新语句,InnoDB会自动加上排他锁;对于查询语句,如果是快照读,由于MVCC的存在,InnoDB不会加任何锁。
- 只有共享锁和共享锁不冲突,其他组合的锁都是冲突的。
从锁的粒度划分
-
全局锁
- 通过
FLUSH TABLES WITH READ LOCK
语句,整个数据库处于只读状态,其他线程的增删改或表结构修改操作都会阻塞。 - 主要应用于全库逻辑备份,确保备份期间数据或表结构不被更新。
- 通过
-
表级锁
-
表锁:通过
LOCK TABLES
语句对表加锁,会限制其他线程及本线程接下来的读写操作。 -
元数据锁(MDL)
:
- 对表进行操作时自动加上。
- CRUD操作加MDL读锁;表结构变更操作加MDL写锁。
- 保证表执行CRUD操作时,防止其他线程对表结构做变更。
-
意向锁
:
- 执行插入、更新、删除操作时,先对表加意向独占锁,再对记录加独占锁。
- 目的是快速判断表里是否有记录被加锁。
-
-
行级锁
- InnoDB引擎支持,MyISAM引擎不支持。
- 记录锁:锁住一条记录,有S锁和X锁之分,满足读写互斥、写写互斥。
- 间隙锁:只存在于可重复读隔离级别,解决幻读现象。
- Next-Key Lock(临键锁):Record Lock + Gap Lock的组合,锁定一个范围及记录本身。
- 插入意向锁:某个区间的某个位置的锁。
- 隐式锁:当前事务不生成锁结构,延迟生成。其他事务根据隐藏字段判断事务是否提交,若提交则自己加锁;若未提交则帮助此事务加锁并等待。
锁与索引的关系
- 行锁基于索引实现,锁定范围是索引记录。
- 索引的选择影响锁的范围和性能,使用索引可减少锁定行数,提高并发性。
- 无索引时,可能退化为表锁,导致大量行被锁定。
插入语句是否会触发间隙锁?
- 普通INSERT
- 如果间隙已经有间隙锁,使用插入意向锁,插入后给插入的数据上隐式锁;如果没有,加隐式锁。
- 唯一约束冲突时的INSERT
- 如果插入的值在锁定范围内且违反唯一约束,会加临键锁。
- 示例:事务A锁定了(1, 10],
INSERT INTO t (id) VALUES (5);
会阻塞,直到事务A提交。
表锁和行锁的作用
- 表锁的作用
- 整体控制:控制整个表的并发访问,确保数据完整性和一致性。
- 粒度大:锁定表时可能影响其他操作,引起锁竞争和性能问题。
- 适用于大批量操作:适合表重建、大量数据加载等场景。
- 行锁的作用
- 细粒度控制:精确控制对表中某行数据的访问,提高并发性能。
- 减少锁冲突:减少锁竞争,提高并发访问效率。
- 适用于频繁单行操作:适合订单系统中的订单修改、删除等操作。
加锁算法
读未提交下
- 增:如果间隙已经有间隙锁,使用插入意向锁,插入后给插入的数据上隐式锁;如果没有,加隐式锁;如果是二级唯一索引,无论哪个隔离级别,插入新记录时遇到唯一二级索引列重复,加临键锁。
- 删:需要获取要删除记录的记录锁,保证删除时其他事务未使用这些数据,并保证删除后其他事务无法操作。
- 改:给需要更改的数据上记录锁。
- 查:普通
SELECT
不上锁,直接读最新数据,不管是否提交;SELECT…FOR UPDATE
或SELECT … LOCK IN SHARE MODE
会上记录锁,不锁间隙。
读已提交下
- 增:同读未提交。
- 删:需要获取要删除记录的记录锁,保证删除时其他事务未使用这些数据,并保证删除后其他事务无法操作。
- 改:给需要更改的数据上记录锁。
- 查:普通
SELECT
不上锁,通过MVCC找到读取的数据;SELECT…FOR UPDATE
或SELECT … LOCK IN SHARE MODE
会上记录锁,不锁间隙。
可重复读下
- 增:如果间隙已经有间隙锁,使用插入意向锁,插入后给插入的数据上隐式锁;如果没有,加隐式锁;如果是二级唯一索引,无论哪个隔离级别,插入新记录时遇到唯一二级索引列重复,加临键锁。
- 删:使用临键锁,防止其他事务在删除的区间内插入数据。
- 改:给需要更改的数据上临键锁。
- 查:普通
SELECT
不上锁,通过MVCC找到读取的数据;SELECT…FOR UPDATE
或SELECT … LOCK IN SHARE MODE
会上临键锁,锁间隙。
串行化读下
- 增:如果间隙已经有间隙锁,使用插入意向锁,插入后给插入的数据上隐式锁;如果没有,加隐式锁;如果是二级唯一索引,无论哪个隔离级别,插入新记录时遇到唯一二级索引列重复,加临键锁。
- 删:使用临键锁,防止其他事务在删除的区间内插入数据。
- 改:给需要更改的数据上临键锁。
- 查:普通查询自动变为
SELECT … LOCK IN SHARE MODE
,上临键锁,锁间隙。
锁释放与操作细节
- 这些锁的释放是在事务提交后释放。
- 删除操作和更新操作类似,删除本质是修改行记录的逻辑删除标识位。
- MVCC只有在读已提交和可重复读中才有。
- 间隙锁只有在可重复读和串行化读中才有。
- 读已提交相对于读未提交只多了个MVCC,用于解决数据可见性问题,保证读到的是已提交的数据。
- 可重复读相对于读已提交相当于把记录锁升级为临键锁,解决(大部分)幻读情况。
- 串行化读相对于可重复读相当于普通读会上锁,解决全部幻读情况。