MySQL-锁
-
锁的分类
-
全局锁
- MySQL全局锁会使用读锁锁定所有库中所有的表。
- 加锁:
FLUSH TABLES WITH READ LOCK;
- 解锁:
UNLOCK TABLES;
- 全局锁加锁后,所有的连接只能读表,加锁的连接进行表中数据的修改会报错。其他连接进行数据修改会阻塞,直到全局锁解锁后返回。一般用在整个库做备份时。
-
表锁
-
行锁
-
InnoDB比MyISAM具有的优势主要是支持事务,以及支持行锁。
行共享锁 允许所有事务去读加锁行,阻止其他事务获得相同行的排他锁。 行排他锁 只允许加锁的事务去读写,阻止其他事务获得共享锁或排他锁。 -
快照读与当前读
快照读 不显式加锁的select语句 不加任何锁 当前读 显示加锁的select与insert、delete、update 加排他锁 -
显式加锁
- 共享锁:
select * from table_name lock in share mode;
- 排他锁:
select * from table_name for update;
- 共享锁:
-
不显式加锁时select不会加锁,且select也可以读取加了锁的行,因为每行数据有多个版本,每次select只需读取其中的数据即可,RC级别下读取最新的数据,RR级别下读取事务开始前的数据,通过MVCC实现。
-
-
加锁方式
-
InnoDB行锁的加锁方式有三种:
-
Record Lock 单个记录上的索引加锁。 Gap Lock 间隙锁,所索引项之间的间隙加锁,不包括记录本身。 Next-Key Lock 锁定一个范围,并缩定记录本身,相当于Record+Gap Lock。
-
-
加锁方式选择
- 通过非索引字段查询时加锁:
- 对整个表加表锁,其他连接对表中所有行均不可以修改。
- 通过唯一索引字段查询时加锁:
- 对聚族索引和此索引中的此行均加锁。
- 通过非唯一索引字段查询时加锁:
- 满足条件的行在此索引和聚族索引中均加锁。
- 通过非索引字段查询时加锁:
-
-
间隙锁
-
在RC级别下会产生幻读(事务中两次读取到的数据行数不同),因为行锁只锁定了当前存在的匹配的行,因此其他事务仍可以插入相同值的新行。导致了RC级别下第一次select查询时对同一key值的所有行加锁,而其他事务仍可以插入key值相同的新行,因此第二次select查询时会导致幻读读到新的行。
-
但在RR级别下,会加入间隙锁,间隙锁会锁定加锁的key值的所有间隙,使其他连接不能插入同key的新行。
-
间隙锁是在RR隔离级别下的,避免了RC级别下存在的当前读幻读问题,当前读会维护所有的索引在其中判断是否含有间隙锁。
-
无索引
- 当使用非索引字段时,会把所有行都加上行排他锁,所有的间隙都加上间隙锁,使其他插入更新等均不可执行。(是否会退化成行锁呢?)
-
唯一索引
- 唯一索引不存在插入同一key的情况,因此不会发生幻读无需加间隙锁。
-
普通索引
- 当使用普通索引字段时,把匹配的key的所有行都加上行排他锁,并在key的间隙加上间隙锁,使其他连接无法插入同key的新行。
-
MVCC和间隙锁
- 在RR级别中,MySQL通过MVCC来解决快照读时的幻读问题,间隙锁解决当前读下的幻读问题。
-
-
元数据锁
-
在之前MySQL事务与DDL(ALERT、DROP等)一同对一张表操作时会出现问题。因此引入了元数据锁(MDL)。
-
在语句或事务执行时,会对表加上元数据锁,使其他连接在事务结束之前DDL语句操作此表时将阻塞,直到结束后才进行操作并返回。
-
-
元数据锁导致的阻塞
- 在有多个连接对此表进行操作时,如果有连接正在进行事务或语句,而一个连接正在为了抢夺这个连接的MDL锁来进行DDL操作而阻塞时,其他查询连接将也阻塞在此,直到ddl进行结束,或者阻塞ddl的连接被断开。
- 因此应尽量避免慢查询以及事务应即使提交,且避免在业务高峰期进行DDL操作。
来源:CSDN
作者:tank59he
链接:https://blog.csdn.net/hu853996234/article/details/103973846