`
OuYangGod
  • 浏览: 54321 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

MySQL InnoDB锁机制(三)

阅读更多

前面两篇文章讨论了MySQL InnoDB的锁类型与加锁方式,这次,我们来看看在不同的场景下,不同的SQL会以什么样的方式加什么类型的锁。

 

在开始之前,我们先了解一下什么是聚族索引?

 

每一张InnoDB表都有且仅有一表特殊的索引,聚族索引(Clustered Index),表中的数据是直接存放在聚族索引的叶子节点页面中,这样,根据聚族索引查询就会比普通索引更快,因为少了一次IO操作。通常,聚族索引就是表的主键;如果表没有主键,那InnoDB会把第一个非空的唯一索引当作聚族索引;如果表既无主键,又无非空的唯一索引,那么InnoDB会创建一个隐藏的索引。表中的其它全部索引,都叫做第二索引(Secondary Index),第二索引中只包含自身索引列和聚族索引列的内容,所以当一个表的主键很长时,其它的索引都会受到影响。

 

为什么要先讲聚族索引呢?因为这对理解InnoDB加锁机制很重要,InnoDB加锁的对象不是返回的数据记录,而是查询这些数据时所扫描过的索引。当我们执行一个锁读(SELECT ... LOCK IN SHARE MODE或者SELECT ... FOR UPDATE)时,InnoDB不是对最终的返回结果加锁,而是对查询这些结果时所扫描的索引加锁,如果被扫描的索引不是聚族索引,那被扫描的索引所指向的聚族索引以及其它指向相同聚族索引的索引也会被加锁。由此可知,当一个锁读无法使用索引的话,InnoDB就是遍历整个表(遍历整个聚族索引),从而把整张表都锁住。

 

我们来看一个例子,首先创建一张表:

CREATE TABLE `tb` (
  `id1` int(11) NOT NULL,
  `id2` int(11) NOT NULL,
  `id3` int(11) NOT NULL,
  `id4` int(11) DEFAULT NULL,
  PRIMARY KEY (`id1`),
  UNIQUE KEY `uidx` (`id2`),
  KEY `idx` (`id3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

 插入一些数据:

mysql> select * from tb;
+-----+-----+-----+------+
| id1 | id2 | id3 | id4  |
+-----+-----+-----+------+
|   1 |   1 |   1 |    1 |
|   5 |   5 |   5 |    5 |
|   9 |   9 |   9 |    9 |
+-----+-----+-----+------+

 会话S1根据id4查询一条记录

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb where id4 = 1 lock in share mode;
+-----+-----+-----+------+
| id1 | id2 | id3 | id4  |
+-----+-----+-----+------+
|   1 |   1 |   1 |    1 |
+-----+-----+-----+------+
1 row in set (0.00 sec)

mysql>

接着会话S2中尝试对id2=5的记录加锁。

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb where id2 = 5 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

发生了锁等待超时,因为会话S1根据非索引字段id4查询,InnoDB会扫描整个聚族索引(字段id1),并对扫描过的聚族索引及所有指向相同聚族索引的其它索引都加锁(本例中所有的索引都被加锁了),所以会话S2在尝试对id2=5的记录加锁时只能等待了。由此可见,正确的设计和使用索引,不光对性能有影响,对并行性的影响也至关重要

 

再看一个例子,在可重复读隔离级别下,会话S1以id3=5(普通索引)字段加锁查询tb表

mysql> select * from tb;
+-----+-----+-----+------+
| id1 | id2 | id3 | id4  |
+-----+-----+-----+------+
|   1 |   1 |   1 |    1 |
|   5 |   5 |   5 |    5 |
|   9 |   9 |   9 |    9 |
+-----+-----+-----+------+
3 rows in set (0.01 sec)

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb where id3=5 for update;
+-----+-----+-----+------+
| id1 | id2 | id3 | id4  |
+-----+-----+-----+------+
|   5 |   5 |   5 |    5 |
+-----+-----+-----+------+
1 row in set (0.01 sec)

mysql>

 会话S2的情况如下

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb where id3 = 5 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tb(id1,id2,id3,id4) values(2,2,2,2);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tb(id1,id2,id3,id4) values(8,8,8,8);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update tb set id4 = 6 where id2 = 5;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update tb set id4 = 6 where id1 = 5;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> 
由结果可知:基于普通索引字段(id3 = 5)查询,在可重复读隔离级别下,InnoDB会以Next-Key Lock(即Gap-Key Lock与Index-Record Lock的组合)的方式对索引加锁,如果被扫描的索引(字段id3 = 5)不是聚族聚引,那被扫描索引指向的聚族索引(id1 = 5),及其它指向相同聚族索引的索引(id2 = 5)都会被加锁。
 
明白了上面的例子,那官网的总结就很容易理解了,在这里简单总结一下:
  1. 在可重复读级别下,InnoDB以Next-Key Lock的方式对索引加锁;在读已提交级别下,InnoDB以Index-Record Lock的方式对索引加锁。
  2. 被加锁的索引如果不是聚族索引,那被锁的索引所指向的聚族索引以及其它指向相同聚族索引的索引也会被加锁。
  3. SELECT * FROM ... LOCK IN SHARE MODE对索引加共享锁;SELECT * FROM ... FOR UPDATE对索引加排他锁。
  4. SELECT * FROM ... 是非阻塞式读,(除Serializable级别)不会对索引加锁。在读已提交级别下,总是查询记录的最新、有效的版本;在可重复读级别下,会记住第一次查询时的版本,之后的查询会基于该版本。例外的情况是在串行化级别,这时会以Next-Key Lock的方式对索引加共享锁。
  5. UPDATE ... WHERE 与DELETE ... WHERE对索引加排他锁。
  6. INSERT INTO ... 以Index-Record Lock的方式对索引加排他锁。
分享到:
评论

相关推荐

    mysql事务与锁机制(存储引擎和锁、MyISAM锁机制、InnoDB锁机制、Next-Key锁、Dead-Lock).docx

    #### 三、InnoDB锁机制 **1、事务基础概念** 事务是数据库操作的基本单位,确保数据的一致性和完整性。InnoDB支持ACID特性(原子性、一致性、隔离性、持久性),并通过多种锁机制来实现这些特性。 **2、锁机制...

    MySQL8.0锁机制和事务

    MySQL 8.0 锁机制和事务 MySQL 8.0 中的锁机制和事务是数据库系统中非常重要的概念。锁机制是指数据库系统中对数据访问的控制机制,而事务是指数据库系统中的一组操作单元。了解锁机制和事务是非常关键的,因为它们...

    InnoDB锁机制学习笔记

    MySQL的引擎简介,InnoDB的锁机制与事务隔离级别

    MySQL高级 锁机制

    MySQL的锁机制是数据库管理系统中用于控制并发操作的重要机制,对于多用户环境下的数据一致性、事务隔离性和系统性能有着至关重要的影响。本文将深入探讨MySQL的高级锁机制,包括表锁和行锁,并提供一些优化建议。 ...

    mysql insert锁机制1

    在MySQL的InnoDB存储引擎中,插入操作不仅涉及到行级锁,还可能涉及Gap锁和Next-Key Locks,这些锁机制的设计是为了防止幻读(Phantom Read)和其他并发问题。 1. 数据库版本:文中提到的是MySQL 5.6.27。不同版本...

    MySQL的锁机制解析

    MySQL的锁机制是数据库管理系统中用于控制并发操作的重要机制,对于保证数据的一致性和完整性起着至关重要的作用。本文将深入解析MySQL中的锁机制,帮助读者理解其工作原理,为面试准备或日常数据库管理提供有力支持...

    mysql索引和锁机制简介

    关于mysql中的innodb存储引擎的索引机制简介,详细介绍了锁机制

    MySQL:锁机制.pdf

    在MySQL中,锁机制是保障数据操作安全的重要组成部分,其主要分为表锁、行锁和间隙锁。本知识点详细解读了MySQL锁机制的定义、分类、特点以及具体的应用案例。 1. 锁的定义和分类 在数据库系统中,锁是用来控制多...

    MYSQL锁机制

    ### MySQL锁机制详解 #### 一、MySQL锁机制概述 MySQL中的锁机制是数据库管理系统用于控制并发事务对数据资源访问的关键技术之一。合理地管理和利用锁机制能够有效地防止数据不一致性和提高系统的并发处理能力。...

    MYSQL锁机制全揭秘

    MySQL锁机制是数据库管理系统中用于协调多个事务或者进程,以保证数据的完整性和一致性的一套规则。在数据库操作中,保证数据并发访问时的一致性、有效性是至关重要的,锁机制正是为此而生。 MySQL支持不同存储引擎...

    MySQL内核:InnoDB存储引擎 卷1.pdf.zip

    深入学习《MySQL内核:InnoDB存储引擎 卷1》,读者可以了解到InnoDB的内部工作机制,如如何处理B+树索引、事务的提交与回滚、锁的实现以及内存管理等内容,这对于优化数据库性能、解决并发问题、设计高效的数据模型...

    mysql 5.6 新特性-innodb

    ### MySQL 5.6 新特性-InnoDB:深入剖析 #### MySQL 5.6 版本简介及重要性 MySQL 5.6 是 MySQL 的一个重要版本,相比于之前的版本(如 MySQL 5.1 和 5.5),它在多个方面进行了显著的改进。这些改进不仅提升了...

    mysql内核 innodb存储引擎

    内容深入,从源代码的角度深度解析了InnoDB的体系结构、实现原理、工作机制,并给出了大量最佳实践,能帮助你系统而深入地掌握InnoDB,更重要的是,它能为你设计和管理高性能、高可用的数据库系统提供绝佳的指导。...

    MySQL内核:InnoDB存储引擎 卷1.pdf

    卷1》由资深MySQL专家,机工畅销图书作者亲自执笔,在以往出版的两本InnoDB介绍性图书的基础之上,更深入地介绍InnoDB存储引擎的内核,例如latch、B+树索引、事务、锁等,从源代码的角度深度解析了InnoDB的体系结构...

Global site tag (gtag.js) - Google Analytics