MySQL系列(三):MySQL中的各种锁你都知道吗?

系列文章:

一、背景

一般的事务隔离级别共有四种,分别对应并发场景下多线程对数据访问的四种方式:

如果通过锁机制,如何实现并发控制了?

 

若只用锁实现隔离级别会导致写会阻塞读。而大部分业务属于读多写少场景,这也是锁机制只能保证并发安全,不能保证并发性能的根本原因。那么,MySQL是如何做并发控制的了?

 

引入快照读后,实现如下:

然而,MySQL在RR隔离级别通过在当前读场景引入间隙锁干掉了幻读现象,使其在RR就已达到了隔离性的标准。所以,最终MySQL的实现方式:

二、锁的种类

按「MySQL实现」->「锁粒度」->「锁用途」对锁进行分类:

2.1、全局锁

MySQL全局锁(Global Lock)是一种特殊的锁类型,用于保证数据库的全局一致性。

 

在 MySQL 中,全局锁可以用于以下情况:

1. 在进行数据恢复时,为了防止其他事务对正在恢复的数据进行修改,可以使用全局锁锁定整个数据库,使得其他事务无法访问数据库。
2. 在进行数据导出时,为了防止其他事务对正在导出的数据进行修改,可以使用全局锁锁定整个数据库,使得其他事务无法访问数据库。
3. 在进行数据备份时,为了防止其他事务对正在备份的数据进行修改,可以使用全局锁锁定整个数据库,使得其他事务无法访问数据库。

加锁方式:

 Flush tables with read lock

解锁方式:

unlock tables 

全局锁是一种非常强大的锁类型,它可以保证数据库的全局一致性。但是,全局锁也会带来一些性能问题,因为它会阻塞其他所有的事务,使得数据库的并发性能下降。因此,在使用全局锁时,需要谨慎考虑其使用场景,并尽量减少其使用时间,以避免对数据库性能的影响。

2.2、表级锁

1、表锁

表锁,顾名思义就是对某个表加锁。如果引擎不支持行锁,那么就会使用表锁,比如MyISAM,或者SQL语句没有命中索引,同时也需要加锁的情况下,就会使用表锁。

2、MDL

MySQL 的 MDL(MetaData Lock)是一种用于管理元数据(MetaData)的锁,它属于 MySQL 数据库的 Server 层。具体来说,MDL 锁用于管理以下元数据:
✓ 表结构:包括表名、列名、列类型等。
✓ 索引:包括索引名、索引列等。
✓ 权限:包括用户权限、角色权限等。
✓ 触发器:包括触发器名、触发条件等。

注意,无论是DML,DDL都会加MDL锁。DML操作加MDL读锁;DDL操作加MDL写锁。

3、意向锁

意向锁,本质上就是空间换时间的产物,是为了提高行锁效率的一个东西。

在 InnoDB 中,我们对某条记录进行锁定时,为了提高并发度,通常都只是锁定这一行记录,而不是锁定整个表。而当我们需要为整个表加 X 锁的时候,我们就需要遍历整个表的记录,如果每条记录都没有被加锁,才可以给整个表加 X 锁。而这个遍历过程就很费时间,这时候就有了意向锁的诞生。

意向锁其实就是标记这个表有没有被锁,如果有某条记录被锁住了,那么就必须获取该表的意向锁。所以当我们需要判断这个表的记录有没有被加锁时,直接判断意向锁就可以了,减少了遍历的时间,提高了效率,是典型的用空间换时间的做法。

MySQL 中有两种意向锁:
✓ Intention Share Lock(IS):表示事务有对表或行进行共享访问。
✓ Intention Exclusive Lock(IX):表示事务有对表或行进行排他访问。

2.3、行级锁

三、注意事项

3.1、业务设计

3.2、使用技巧

✧ 尽量使用limit语句,控制加锁范围。DML相同数量的数据,使用limit语句减少了加锁范围,有效避免了锁等待。
✧ 同一组资源,不同事务应按相同顺序访问。加锁是依次、按顺序获取的过程,为了减少死锁概率,对同一组资源尽量用相同顺序访问。
✧ 对于一组资源的访问,能正向则尽量不反向操作。反向范围查询由于遍历方向的问题,可能会存在"不必要"的加锁。。
✧ 唯一索引的插入,需要保证不存在唯一性冲突。
✧ 尽量使用联合索引,而不是一个SQL走多个索引。MySQL引入的Index Merge优化会引入死锁,使用联合索引可防止优化器使用index merge。

 
posted @ 2024-11-29 16:44  qhlhaylee  阅读(20)  评论(0编辑  收藏  举报