Mysql锁详解

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: mysql锁

 前言

MySQL中不同的存储引擎支持不同的锁机制。比如

  • MyISAMMEMORY存储引擎采用的是表级锁(table-level locking);
  • BDB 存储引擎采用的是页面锁(page-level locking),但也支持表级锁;
  • InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

从对数据操作的类型来看,可以分为:

  1. 读锁(共享锁):事务T对数据对象A加上读锁,则事务T只可以读A不能修改,其他事务也只能对数据A加读锁。
  2. 写锁(排它锁)事务T对数据对象A加上写锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。

一、表级锁、行级锁、页面锁的区别

    • 表级锁:偏向MyISM存储引擎,开销小,加锁块;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
    • 行级锁:偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率最低,并发度最高。 InnoDB与MyISAM最大不不同有两点,一是支持事务,                         二 是采用了行级锁
    • 页面锁开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

    表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用; 而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。

    二、MyISAM表锁

    2.1 查看表锁争用情况

      • Table_locks_immediate 表示立即释放表锁数
      • Table_locks_waited 表示需要等待的表锁数

      如果waited值比较大,说明存在严重的表锁争用情况。

      20210226160526448.png

      2.2 如何加表锁

      MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATEDELETEINSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,如果需要显式加锁,必须同时取得所有涉及到表的锁。例如:

      Lock tables 表1 read local, 表2 read local;
      Select sum(total) from 表1;
      Select sum(total) from 表2;
      Unlock tables;

      image.gif2.3 MyISAM锁调度

      MyISAM 存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么,一个进程请求某个 MyISAM 表的读锁,同时另一个进程也请求同一表的写锁,MySQL 如何处理呢?

      答案是写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插 到读锁请求之前!这是因为 MySQL 认为写请求一般比读请求要重要。这也正是 MyISAM 表 不太适合于有大量更新操作和查询操作应用的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。

      三、InnoDB锁问题

      InnoDB默认使用的是行锁:行锁开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最低,并发度最高。

      可以通过检查 InnoDB_row_lock 状态变量来分析系统上的行锁的争夺情况

      20210227103438935.png

      除了读锁与写锁之外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB 还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

        • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁。
        • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁。

        示例SQL准备:

        CREATE TABLE demo_innodb_lock(
           id INT(11),
           name VARCHAR(16),
           sex VARCHAR(1)
        )ENGINE = INNODB DEFAULT CHARSET = utf8
        INSERT INTO demo_innodb_lock VALUES (1,'100','1');
        INSERT INTO demo_innodb_lock VALUES (1,'200','0');
        INSERT INTO demo_innodb_lock VALUES (2,'90','0');
        INSERT INTO demo_innodb_lock VALUES (3,'400','1');
        INSERT INTO demo_innodb_lock VALUES (4,'300','0');
        INSERT INTO demo_innodb_lock VALUES (5,'500','1');
        INSERT INTO demo_innodb_lock VALUES (6,'600','0');
        INSERT INTO demo_innodb_lock VALUES (7,'700','1');
        INSERT INTO demo_innodb_lock VALUES (8,'800','0');
        CREATE INDEX idx_id ON demo_innodb_lock(id);
        CREATE INDEX idx_name ON demo_innodb_lock(name);

        image.gif

        把自动提交关闭

        SET autocommit = 0;

        image.gif

        示例1:对于UPDATE、DELETE、INSERT语句,InnoDB会自动给涉及数据集加排他锁(X)  

        20210227140059274.png

        此时由于事务没有提交,再开一个窗口对同一行进行更新操作,会发现处于阻塞状态

        20210227140149371.png

        当第一个窗口中的事务执行commit;后,释放排它锁,如果第二个窗口中锁等待没有超时,则会立即执行

        示例2:行锁升级为表锁

        在示例准备中我们给id和name创建了索引,但是此时索引失效了,执行更新操作后不提交

        20210227143759549.png

        在第二个窗口执行更新并提交

        20210227144236185.png

        此时在第一个窗口中查询发现,id=4的数据并没有发生改变,问题是操作的不是同一行数据,说明此时已经升级为表锁了,原因就是索引失效。

        20210227144343887.png

        提交窗口一中的事务,释放表锁,再次查询

        20210227144534687.png

        3.1 InnoDB行锁的实现方式

          1. InnoDB行锁是通过给索引上的索引项加锁来实现的,InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。
          2. 由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
          3. 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。
          4. 即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL 认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。

          3.2 间隙锁Next-Key 锁)

          当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙

          (GAP)”,InnoDB 也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key 锁)。

          示例:

          20210227145149662.png

          此时去执行这样一条更新语句时,由于数据库中没有id=2的数据,那么就意味着存在间隙。

          20210227145327306.png

          窗口1中事务没提交的情况下,在窗口2插入一条ID=2的数据,发现插入不进去,证明了是存在间隙锁的;提交窗口1中的事务后,窗口2中SQL执行成功。

          20210227145555529.png

          InnoDB 使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,另外一方面,是为了满足其恢复和复制的需要。

          相关实践学习
          如何在云端创建MySQL数据库
          开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
          全面了解阿里云能为你做什么
          阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
          相关文章
          |
          2月前
          |
          SQL 关系型数据库 MySQL
          MySQL 锁
          MySQL里常见的几种锁
          57 3
          |
          2月前
          |
          存储 关系型数据库 MySQL
          优化 MySQL 的锁机制以提高并发性能
          【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
          118 1
          |
          2月前
          |
          关系型数据库 MySQL Java
          MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock
          本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。
          236 2
          |
          2月前
          |
          存储 关系型数据库 MySQL
          MySQL数据库锁:共享锁和独占锁
          本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
          92 1
          |
          3月前
          |
          监控 关系型数据库 MySQL
          MySQL锁机制与解决死锁问题
          MySQL锁机制与解决死锁问题
          344 5
          |
          2月前
          |
          存储 关系型数据库 MySQL
          MySQL锁,锁的到底是什么?
          【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
          83 0
          |
          2月前
          |
          关系型数据库 MySQL 数据库
          mysql锁详解
          通过理解并合理运用MySQL中的锁机制,开发者可以有效管理数据库并发访问,平衡性能与数据一致性需求。更多关于MySQL锁的深入探讨和最佳实践,请参考专业的数据库管理资源[[深入MySQL锁机制详解
          60 0
          |
          3月前
          |
          关系型数据库 MySQL 数据库
          Mysql的锁
          本文介绍了MySQL中表级锁和行级锁的区别,其中MyISAM仅支持表级锁,而InnoDB支持表级锁和行级锁,默认为行级锁。表级锁锁定整个表,实现简单,资源消耗少,但并发度低;行级锁仅锁定相关记录,减少冲突,提高并发度,但加锁开销大。此外,还介绍了共享锁和排他锁的概念及意向锁的作用。
          |
          3月前
          |
          存储 SQL 关系型数据库
          MySQL 的锁机制,那么多的锁,该怎么区分?
          MySQL 的锁机制,那么多的锁,该怎么区分?
          50 0
          |
          4月前
          |
          监控 关系型数据库 MySQL
          在Linux中,mysql的innodb如何定位锁问题?
          在Linux中,mysql的innodb如何定位锁问题?