MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁

文章目录

  • 一、行锁
    • Q:MySQL行锁有哪些使用场景
    • Q:MySQL那些命令会导致发生行锁?
  • 二、间隙锁(Gap Lock)
    • 间隙锁有哪些使用场景
  • 三、临建锁(Next-Key Lock)
  • 四、表锁
    • 意向锁(Intention Lock)
    • 作用
      • 为什么意向锁是表级锁呢?
      • 意向锁怎么支持表锁和行锁并存?
      • 如何查看

一、行锁

行级锁是MySQL中的一种锁定机制,它可以对数据库表中的单独一行进行锁定。相比于表级
锁和页锁,行级锁的粒度更小,因此在处理高并发事务时,能提供更好的并发性能和更少的
锁冲突。然而,行级锁也需要更多的内存和CPU资源,因为需要对每一行都进行管理。
在MySQL中,行级锁主要由InnoDB存储引擎提供。InnoDB支持两种类型的行级锁:共享锁
(S锁)和排他锁(X锁)。

  1. 共享锁(S锁):共享锁也称为读锁,它允许一个事务读取一行数据。当一行数据被共享
    锁锁定时,其他事务可以读取这行数据,但不能对其进行修改。
  2. 排他锁(X锁):排他锁也称为写锁,它允许一个事务读取和修改一行数据。当一行数据
    被排他锁锁定时,其他事务不能读取也不能修改这行数据。
    在实际使用中,InnoDB还提供了一种名为“间隙锁”(Gap Lock)的特性。间隙锁不仅锁
    定一个具体的行,还锁定它前后的“间隙”,即这一行之前的行和之后的行之间的空间。间
    隙锁可以防止其他事务插入新的行到已锁定行的前后,从而可以解决一些并发问题。
    值得注意的是,行级锁只在事务中有效,也就是说,只有在一个事务开始(BEGIN)后并在
    事务提交(COMMIT)或回滚(ROLLBACK)之前,才能对数据行进行锁定。如果在非事务
    环境中执行SQL语句,那么InnoDB会在语句执行结束后立即释放所有的锁。

Q:MySQL行锁有哪些使用场景

MySQL中的行级锁(Row Level Locks)通常在以下几种场景中被使用:

  1. 高并发读写操作:在需要高并发读写操作的场景中,行级锁可以提高性能和并发性,因为
    它允许多个事务并发地操作不同的行。
  2. 单行操作:对于需要操作单行数据的SQL语句(例如基于主键或者唯一索引的UPDATE、
    DELETE和INSERT语句),行级锁可以提供较好的并发性和性能。
  3. 短期锁:在需要对数据行进行短时间锁定的情况下,行级锁可以防止长时间阻塞其他事
    务。
  4. 实现并发控制:在需要确保数据一致性和隔离性的事务中,行级锁是实现并发控制的重要
    机制。
  5. 复杂的事务处理:在需要对多行数据进行复杂处理的事务中,可以使用行级锁来锁定这些
    行,防止在事务处理过程中数据被其他事务修改。
    使用行级锁需要注意,由于行级锁的锁定粒度较小,它可能会消耗更多的系统资源(例如内
    存和CPU),特别是在处理大量数据时。此外,使用行级锁也可能导致死锁,需要使用合适
    的策略来避免死锁,例如在事务中按照一定的顺序锁定行。

Q:MySQL那些命令会导致发生行锁?

在MySQL中,主要是InnoDB存储引擎提供了行级锁(Row Level Locking)。一般来说,以
下这些类型的操作会导致InnoDB对数据行进行加锁:

  1. SELECT … FOR UPDATE:这种查询会对选定的行添加一个排他锁(X锁),这意味着
    其他事务不能修改这些行,也不能对这些行添加共享锁。
  2. SELECT … LOCK IN SHARE MODE:这种查询会对选定的行添加一个共享锁(S
    锁),这意味着其他事务不能修改这些行,但可以对这些行添加共享锁。
  3. INSERT:插入操作会对新添加的行添加一个排他锁(X锁)。
  4. UPDATE:更新操作会对被更新的行添加一个排他锁(X锁)。
  5. DELETE:删除操作会对被删除的行添加一个排他锁(X锁)。
    这些加锁操作都是在事务中进行的,即只有在事务开始(BEGIN)后并在事务提交
    (COMMIT)或回滚(ROLLBACK)之前,才会对数据行进行加锁。如果在非事务环境中执
    行上述SQL语句,那么InnoDB会在语句执行结束后立即释放所有的锁。
    请注意,加锁的粒度和范围取决于WHERE子句中用到的索引。如果WHERE子句中用到了唯
    一索引(例如主键索引),那么InnoDB只会锁定匹配的行。如果没有用到唯一索引,那么
    InnoDB可能会锁定更多的行,甚至是整个表,这就可能导致锁冲突和性能问题。
    此外,InnoDB还支持间隙锁(Gap Locks)和临键锁(Next-Key Locks),这两种锁都可以
    在某些情况下提供更好的并发控制。

二、间隙锁(Gap Lock)

间隙锁(Gap Locks)是MySQL InnoDB存储引擎提供的一种锁定机制。它锁定的不是具体
的行记录,而是两个索引之间的间隙(或者说区间),这样可以防止新的记录插入到该间
隙,确保数据的一致性和事务的隔离性。
间隙锁常常与记录锁(Record Locks)一起使用,共同形成Next-Key锁,保护索引记录的范
围查询和扫描操作。
以下是间隙锁的主要类型:

  1. 区间-区间间隙锁:锁定两个索引键之间的间隙,或者是第一个索引键之前的间隙。
  2. 区间-记录间隙锁:锁定一个索引键和一个记录之间的间隙。
  3. 记录-区间间隙锁:锁定一个记录和一个索引键之间的间隙。
    间隙锁的存在,主要是为了解决幻读问题。所谓幻读,是指在一个事务内读取某个范围的记
    录时,另外一个事务在该范围内插入了新的记录,当第一个事务再次读取该范围的记录时,
    会发现有些原本不存在的记录,这就是幻读。
    举例来说,假设我们有一个存储学生信息的表,有一个事务A要查询年龄在10-20之间的学
    生,它在查询前会对这个区间加锁。此时如果有另一个事务B想要插入一个年龄为15的学生,
    由于这个年龄的范围已经被事务A锁定,所以事务B必须等待,直到事务A完成,释放锁。这
    样就避免了幻读的产生。
    值得注意的是,由于间隙锁会锁定范围,如果并发事务较多且涉及的数据范围有交集,可能
    会引发性能问题,甚至死锁。因此,在设计数据库和选择隔离级别时,需要综合考虑数据一
    致性和并发性能。

间隙锁有哪些使用场景

间隙锁(Gap Locks)在MySQL数据库的InnoDB存储引擎中主要用于以下场景:

  1. 防止幻读:间隙锁的主要目的是防止其他事务在已经锁定的范围内插入新的行。这可以避
    免"幻读"问题,即一个事务在读取某个范围内的所有行时,另一个事务插入了一个新行,
    当第一个事务再次读取该范围时,会发现有一个"幻影"行。
  2. 范围查询:在执行范围查询时,如果事务需要对查询结果进行更新或删除,那么间隙锁可
    以保证在事务执行期间,不会有新的行插入到查询范围中。
    例如,以下事务会在Orders表的OrderID列值在1到100之间的所有行上设置排他锁,并在这
    些行的间隙上设置间隙锁:
START TRANSACTION;
SELECT * FROM Orders WHERE OrderID BETWEEN 1 AND 100 FOR UPDATE;
COMMIT;
  1. 防止死锁:在某些情况下,间隙锁可以帮助防止死锁。如果没有间隙锁,那么两个事务可
    能都会试图在同一位置插入一个新行,导致彼此等待对方释放锁,从而形成死锁。
    需要注意的是,间隙锁在可重复读(REPEATABLE READ)和序列化(SERIALIZABLE)这两
    个隔离级别下才会使用,在读已提交(READ COMMITTED)和读未提交(READ
    UNCOMMITTED)这两个隔离级别下,InnoDB不会使用间隙锁。

MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第1张图片
MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第2张图片
可以看到将5–11这些数据都锁住了,这种情况下其它的事务想要去在这个1到11的id区间内做数据修改是会被阻塞的,知道我们将事务提交或者回滚将锁释放才行
MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第3张图片
MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第4张图片

三、临建锁(Next-Key Lock)

Next-Key 可以理解为一种特殊的间隙锁,也可以理解为一种特殊的算法。通过临建锁可以解决幻读的问题。 每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。需要强调的一点是,InnoDB 中行级锁是基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。
MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第5张图片

MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第6张图片
MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第7张图片

四、表锁

意向锁(Intention Lock)

意向锁是表锁,为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。

作用

意向锁的作用是告诉其他事务,当前事务要获取某个页的行锁,以避免其他事务误判并尝试获取该页的表锁。意向锁的引入可以提高并发性能,减少锁冲突。

为什么意向锁是表级锁呢?

当我们需要加一个排他锁时,需要根据意向锁去判断表中有没有数据行被锁定(行锁);
(1)如果意向锁是行锁,则需要遍历每一行数据去确认;
(2)如果意向锁是表锁,则只需要判断一次即可知道有没数据行被锁定,提升性能。

意向锁怎么支持表锁和行锁并存?

(1)首先明确并存的概念是指数据库同时支持表、行锁,而不是任何情况都支持一个表中同
时有一个事务A持有行锁、又有一个事务B持有表锁,因为表一旦被上了一个表级的写锁,肯
定不能再上一个行级的锁。
(2)如果事务A对某一行上锁,其他事务就不可能修改这一行。这与“事务B锁住整个表就
能修改表中的任意一行”形成了冲突。所以,没有意向锁的时候,让行锁与表锁共存,就会
带来很多问题。于是有了意向锁的出现,如前面所言,数据库不需要在检查每一行数据是否
有锁,而是直接判断一次意向锁是否存在即可,能提升很多性能。

MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第8张图片

如何查看

当我执行行锁的时候会为这个表添加一个意向锁,这个意向锁是什么类型取决于你为行锁添加的是什么类型
MySQL中的行锁、临建锁、间隙锁和表锁中的意向锁_第9张图片
我这里是要给意向排他锁,是因为我行锁用的是排他锁。

你可能感兴趣的:(mysql,数据库,锁)