锁的分类(二)
- 简介
为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,
但是管理锁是很耗资源的事情(涉及获取、检查、释放锁等动作)。因此数据库系统需要在高 并发响应和系统性能两方面进行平衡,
这样就产生了“锁粒度(Lock granularity)”的概念。
对一条记录加锁影响的也只是这条记录而已,我们就说这个锁的粒度比较细;其实一个事务也可以在表级别进行加锁,自然就被称之为表级锁或者表锁,
对一个表加锁影响整个表中的记录,我们就说这个锁的粒度比较粗。锁的粒度主要分为表级锁、页级锁和行锁
- 表锁
该锁会锁定整张表,它是MySQL中最基本的锁策略,并不依赖于存储引擎(不管你是MySQL的什么存储引擎,对于表锁的策略都是一样的),
并且表锁是开销最小的策略(因为粒度比较大)。由于表级锁一次会将整个表锁定,所以可以很好的避免死锁问题。当然,锁的粒度大
所带来最大的负面影响就是出现锁资源争用的概率也会最高,导致并发率大打折扣
表级别的元数据锁
在对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,InnoDB存储引擎是不会为这个表添加表级别的S锁或者X锁的。
在对某个表执行一些诸如ALTER TABLE、DROP TABLE这类的DDL语句时,其他事务对这个表并发执行诸如SELECT、INSERT、
DELETE、UPDATE的语句会发生阻塞。同理,某个事务中对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,在其他
会话中对这个表执行DDL语句也会发生阻塞。这个过程其实是通过在server层使用一种称之为元数据锁(英文名:Metadata Locks,
简称MDL)结构来实现的
表级别的S锁、X锁
一般情况下,不会使用InnoDB存储引擎提供的表级别的S锁和X锁。只会在一些特殊情况下,比方说崩溃恢复过程中用到。
比如,在系统变量autocommit=0,innodb_table_locks=1时,手动获取InnoDB存储引擎提供的表t的S锁或者X锁可以这么写:
LOCK TABLES t READ:InnoDB存储引擎会对表t加表级别的S锁
LOCK TABLES t WRITE:InnoDB存储引擎会对表t加表级别的X锁
- 代码案例
# 查看已经加锁的表
show open tables where in_use > 0
# 为mylock表加锁
lock table mylock read;
# 释放锁
unlock tables;
-
结论
-
代码演示
# 在第1个连接中,开启1个事务
begin;
# 开启1个读锁
lock table mylock read;
# 测试自己是否可读
select * from mylock;
# 测试自己是否可写,执行报错
insert into mylock ...
# 测试自己是否可以操作其他表,执行报错
select * from user;
# 打开1个新的连接,测试在新的连接中是否可以读这个表
select * from mylock;
# 在第2个连接中测试是否可以写这张表,处于等待状态
insert into ...
# 在第1个连接中释放这个锁或者结束这个会话之后,其他连接才可以写这张表
意向锁
InnoDB 支持 多粒度锁(multiple granularity locking) ,它允许 行级锁 与 表级锁 共存,而意向锁就是其中的一种表锁
意向锁是由存储引擎 自己维护的 ,用户无法手动操作意向锁,在为数据行加共享或者排他锁之前,InooDB 会先获取该数据行 所在数据表的对应意向锁
使用场景:当用户想为某个表添加1个共享锁或排他锁的时候,这时需要把表中的所有数据检索1遍,检查表中是否有锁,如果表中的数据较多,这时检索的时候就会消耗很多资源;
所以当我们为某个表或某个页添加锁后,数据库会自动为上一级添加1个意向锁;其他用户想要为这个表再次添加锁的时候,就能直接知道这张表已经添加了锁,不需要再检索整个表
- 案例
# 添加意向共享锁:添加共享锁的时候会自动添加意向共享锁
SELECT column FROM table ... LOCK IN SHARE MODE;
# 添加意向排他锁:添加排他锁的时候会自动添加意向排他锁
SELECT column FROM table ... FOR UPDATE;
# 案例1
# 为某1行添加X锁,数据库会自动为页上添加意向X锁
select * from user where id = 7 for updata;
# 这时在新的连接或新的事务中继续添加锁时,就不会检索该表中的所有数据
# 案例2
# 为表中的某1行添加1个S锁,数据库自动为页添加1个意向S锁
# 为该表的另1行添加1个S锁,没有冲突,数据库自动为页添加1个意向S锁,这2个意向S锁是兼容的
- 结论
1. InnoDB 支持 多粒度锁 ,特定场景下,行级锁可以与表级锁共存。
2. 意向锁之间互不排斥,但除了 IS 与 S 兼容外, 意向锁会与 共享锁或排他锁互斥 。
3. IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突。
4. 意向锁在保证并发性的前提下,实现了 行锁和表锁共存 且 满足事务隔离性 的要求