这篇文章给大家介绍mysql中怎么实现 innodb锁机制,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
InnoDB实现标准的行级锁定,其中有两种类型的锁定:共享锁(S)和排他锁(X)。
1)共享锁允许持有该锁的事务读取一行数据。
2)排他锁允许持有该锁的事务更新或删除一行数据。
如果事务T1在行r上持有一个共享锁(S),那么来自其他不同事务T2的对行r上的锁的请求将按以下方式处理:
1)T2可以立即获得行r的共享锁,T1和T2都在r上保持了S锁。
2)T2不能立即获取到排它锁。
如果事务T1在行r上持有排他(X)锁,则不能立即批准某个不同事务T2对r上任一类型的锁的请求。 相反,事务T2必须等待事务T1释放对行r的锁定。
InnoDB支持多种粒度锁定,允许行锁和表锁并存。 例如,诸如LOCK TABLES ... WRITE之类的语句对指定表采用排他锁(X锁)。 但是有一个问题,如果一个事务对一张表的某条数据进行加锁,这个时候如果有另外一个线程想要用LOCK TABLES进行锁表,这时候数据库要怎么知道哪张表的哪条数据被加了锁,一张张表一条条数据去遍历是不可行的。 为了使在多个粒度级别上的锁定变得切实可行,InnoDB使用了意图锁定。 意向锁是表级锁,指示事务稍后对表中的行需要哪种类型的锁(共享锁或排他锁)。
有两种类型的意图锁:
1)意向共享锁(IS)表示事务打算对表中的各个行设置共享锁。
2)意向排他锁(IX)表示事务打算对表中的各个行设置排他锁。
例如,SELECT ... LOCK IN SHARE MODE设置IS锁定,而SELECT ... FOR UPDATE设置IX锁定。
意向锁定协议如下:
1)事务在获取表中某行的共享锁之前,它必须首先获取该表中的IS锁或更强的锁。
2)事务在获取表中某行的排它锁之前,它必须首先获取该表中的IX锁。
表级锁类型的兼容性汇总在以下矩阵中:
X | IX | S | IS | |
X | 冲突 | 冲突 | 冲突 | 冲突 |
IX | 冲突 | 兼容 | 冲突 | 兼容 |
S | 冲突 | 冲突 | 兼容 | 兼容 |
IS | 冲突 | 兼容 | 兼容 | 兼容 |
如果一个锁与现有锁兼容,则将其授予请求的事务,但如果与现有锁冲突,则不授予该锁。 事务等待直到冲突的现有锁被释放。 如果锁定请求与现有锁定发生冲突,并且由于可能导致死锁而无法被授予,则会发生错误。
意向锁除了全表请求(例如LOCK TABLES ... WRITE)外,不阻止任何其他内容。 意图锁定的主要目的是表明某人正在锁定表中的行或要锁定表中的行。
在SHOW ENGINE INNODB STATUS和InnoDB监视器输出中,意图锁定的事务数据看起来类似于以下内容:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
记录锁定是对索引记录的锁定。 例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 防止任何其他事务插入,更新或删除t.c1值为10的行。记录锁始终锁定索引记录,即使没有定义索引的表也是如此。 对于这种情况,InnoDB创建一个隐藏的聚集索引,并将该索引用于记录锁定。
记录锁定的事务数据在SHOW ENGINE INNODB STATUS和InnoDB监视器输出中看起来类似于以下内容:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` trx id 10078 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 8000000a; asc ;; 1: len 6; hex 00000000274f; asc 'O;; 2: len 7; hex b60000019d0110; asc ;;
间隙锁是对索引记录之间的间隙的锁定,或者是对第一个或最后一个索引记录之前的间隙的锁定。例如:SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;防止其他事务将10到20之间的值插入到t.c1的列上,无论该列中是否已经存在这样的值,因为该范围内所有现有值之间的间隙是锁定的。
间隙可能跨越单个索引值,多个索引值,甚至为空。间隙锁是性能和并发性之间权衡的一部分,并且在某些事务隔离级别而非其他级别中使用。
对于查询唯一行的语句时,锁定行时使用唯一索引,不需要间隙锁定。 (这不包括搜索条件仅包含多列唯一索引的某些列的情况;在这种情况下,会发生间隙锁定。)例如,如果id列具有唯一索引,则以下语句仅使用 ID值为100的行的索引记录锁,其他会话是否在前面的间隙中插入行都没有关系:
SELECT * FROM child WHERE id = 100;
如果id未建立索引或具有非唯一索引,则该语句会锁定前面的间隙。
在这里还值得注意的是,可以通过不同的事务将冲突的锁保持在间隙上。 例如,事务A可以在间隙上保留一个共享的间隙锁(间隙S锁),而事务B可以在同一间隙上保留排他的间隙锁(间隙X锁)。允许冲突的间隙锁的原因是,如果从索引中清除记录,则必须合并由不同事务保留在记录上的间隙锁。
InnoDB中的间隙锁唯一目的是防止其他事务插入间隙。 间隙锁可以共存。 一个事务进行的间隙锁定不会阻止另一事务对相同的间隙进行间隙锁定。 共享间隙锁和排他间隙锁之间没有区别。 它们彼此不冲突,并且执行相同的功能。
间隙锁定可以显式禁用。 如果将事务隔离级别更改为READ COMMITTED或启用innodb_locks_unsafe_for_binlog系统变量(现已弃用),则会发生这种情况。 在这种情况下,将禁用间隙锁定进行搜索和索引扫描,并且仅将其用于外键约束检查和重复键检查。
Next-Key Lock是索引记录上的记录锁定和索引记录之前的间隙上的间隙锁定的组合,即记录锁和间隙锁的组合。
InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,会在遇到的索引记录上设置共享或互斥锁。 因此,行级锁实际上是索引记录锁。 索引记录上的next-key lock也会影响该索引记录之前的“间隙”。 即,next-key lock是索引记录锁定加上索引记录之前的间隙上的间隙锁定。 如果一个会话在索引中的记录R上具有共享或排他锁,则另一会话不能按照索引顺序在R之前的间隙中插入新的索引记录。
假设索引包含值10、11、13和20。此索引的可能的next-key lock涵盖以下间隔,其中,圆括号表示排除区间端点,方括号表示包括端点:
(-∞, 10] (10, 11] (11, 13] (13, 20] (20, +∞)
对于最后一个间隔,next-key lock将间隙锁定在索引中的最大值上方,此next-key lock仅锁定最大索引值之后的间隙。
默认情况下,InnoDB以REPEATABLE READ事务隔离级别运行。 在这种情况下,InnoDB使用next-key lock进行搜索和索引扫描,这可以防止幻读问题。
next-key lock的事务数据在SHOW ENGINE INNODB STATUS和InnoDB监视器输出中看起来类似于以下内容:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` trx id 10080 lock_mode X Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 8000000a; asc ;; 1: len 6; hex 00000000274f; asc 'O;; 2: len 7; hex b60000019d0110; asc ;;
插入意图锁定是一种在行插入之前通过INSERT操作设置的间隙锁定的类型。 此锁发出插入意图的信号是,在同一个索引间隙中,如果多个事务未插入间隙中的相同位置,则无需等待插入到同一索引间隙中的多个事务。 假设有索引记录,其值分别为4和7。单独的事务分别尝试插入值5和6,在获得插入行的排他锁之前,每个事务都使用插入意图锁来锁定4和7之间的间隙,但不要互相阻塞,因为行是无冲突的。
下面的示例演示了在获得对插入记录的排他锁之前,使用插入意图锁的事务。 该示例涉及两个客户端A和B。
客户端A创建一个包含两个索引记录(90和102)的表,然后启动一个事务,该事务将排他锁放置在ID大于100的索引记录上。排他锁在记录102之前包括一个间隙锁:
mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; mysql> INSERT INTO child (id) values (90),(102); mysql> START TRANSACTION; mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE; +-----+ | id | +-----+ | 102 | +-----+
客户B开始交易以将记录插入空白。 事务在等待获得排他锁的同时获取插入意图锁。
mysql> START TRANSACTION; mysql> INSERT INTO child (id) VALUES (101);
插入意图锁定的事务数据在SHOW ENGINE INNODB STATUS和InnoDB监视器输出中看起来类似于以下内容:
RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child` trx id 8731 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000066; asc f;; 1: len 6; hex 000000002215; asc " ;; 2: len 7; hex 9000000172011c; asc r ;;...
AUTO-INC锁是一种特殊的表级锁,由插入到具有AUTO_INCREMENT列的表中的事务获取。 在最简单的情况下,如果一个事务正在向表中插入值,则任何其他事务都必须等待自己在该表中进行插入,以便第一个事务插入的行接收连续的主键值。
innodb_autoinc_lock_mode配置选项控制用于自动增量锁定的算法。 它使您可以选择如何在可预测的自动增量值序列与插入操作的最大并发性之间进行权衡。
InnoDB支持包含空间列的列的空间索引,要处理涉及SPATIAL索引的操作的锁定,next-key lock不能很好地支持REPEATABLE READ或SERIALIZABLE事务隔离级别。 多维数据中没有绝对排序概念,因此不清楚哪个是next key。
为了支持具有SPATIAL索引的表的隔离级别,InnoDB使用predicate locks。 SPATIAL索引包含最小边界矩形(MBR)值,因此InnoDB通过在用于查询的MBR值上设置谓词锁定来强制对索引进行一致的读取。 其他事务不能插入或修改将匹配查询条件的行。
关于mysql中怎么实现 innodb锁机制就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。