MySQL 8.0 常见锁介绍(一)

2021/6/7 19:26:03

本文主要是介绍MySQL 8.0 常见锁介绍(一),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一.概述

数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外。MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定,行级锁定和页级锁定。

1.表级锁定(table-level)

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。

当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。

使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。

2.行级锁定(row-level)

行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。

虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。

使用行级锁定的主要是InnoDB存储引擎。

3.页级锁定(page-level)

页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。

在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。

使用页级锁定的主要是BerkeleyDB存储引擎。

总的来说,MySQL这3种锁的特性可大致归纳如下:

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

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

二.InnoDB的八种锁

目前MySQL最常使用且支持事务的存储引擎是InnoDB,此处介绍InnoDB存储引擎的锁。

  • 行锁(Record Locks)
  • 间隙锁(Gap Locks)
  • 临键锁(Next-key Locks)
  • 共享锁/排他锁(Shared and Exclusive Locks)
  • 意向共享锁/意向排他锁(Intention Shared and Exclusive Locks)
  • 插入意向锁( Intention Locks)
  • 自增锁(Auto-inc Locks)
  • 空间索引(Predicate Locks for Spatial Indexes)

1、行锁
MySQL的官方文档中有以下描述:

A record lock is a lock on an index record. Record locks always lock
index records, even if a table is defined with no indexes. For such
cases, InnoDB creates a hidden clustered index and uses this index for
record locking.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

行锁一定是作用在索引上。

2、间隙锁

MySQL的官方文档中有以下描述: A gap lock is a lock on a gap between index records,
or a lock on the gap before the first or after the last index record。
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

表明间隙锁一定是开区间,比如(3,5)或者。在MySQL官网上还有一段非常关键的描述:

Gap locks in InnoDB are “purely inhibitive”, which means that their
only purpose is to prevent other transactions from inserting to the
gap. Gap locks can co-exist. A gap lock taken by one transaction does
not prevent another transaction from taking a gap lock on the same
gap.
There is no difference between shared and exclusive gap locks. They do
not conflict with each other, and they perform the same function.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

这段话表明间隙锁在本质上是不区分共享间隙锁或互斥间隙锁的,而且间隙锁是不互斥的,即两个事务可以同时持有包含共同间隙的间隙锁。这里的共同间隙包括两种场景:其一是两个间隙锁的间隙区间完全一样;其二是一个间隙锁包含的间隙区间是另一个间隙锁包含间隙区间的子集。间隙锁本质上是用于阻止其他事务在该间隙内插入新记录,而自身事务是允许在该间隙内插入数据的。也就是说间隙锁的应用场景包括并发读取、并发更新、并发删除和并发插入。

MySQL的官方文档中有以下描述:

Gap locking can be disabled explicitly. This occurs if you change the
transaction isolation level to READ COMMITTED. Under these
circumstances, gap locking is disabled for searches and index scans
and is used only for foreign-key constraint checking and duplicate-key
checking.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

这段话表明,在RU和RC两种隔离级别下,即使你使用select … in share mode或select … for update,也无法防止幻读(读后写的场景)。因为这两种隔离级别下只会有行锁,而不会有间隙锁。这也是为什么示例中要规定隔离级别为RR的原因。

3、临键锁

MySQL的官方文档中有以下描述:

A next-key lock is a combination of a record lock on the index record
and a gap lock on the gap before the index record.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

    这句话表明临键锁是行锁+间隙锁,即临键锁是是一个左开右闭的区间,比如(3,5]。

MySQL的官方文档中有以下重要描述:

By default, InnoDB operates in REPEATABLE READ transaction isolation
level. In this case, InnoDB uses next-key locks for searches and index
scans, which prevents phantom rows.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

InnoDB的默认事务隔离级别是RR,在这种级别下,如果你使用select … in share mode或者select … for update语句,那么InnoDB会使用临键锁,因而可以防止幻读;但即使你的隔离级别是RR,如果你这是使用普通的select语句,那么InnoDB将是快照读,不会使用任何锁,因而还是无法防止幻读。

4、共享锁/排他锁

MySQL的官方文档中有以下描述:

InnoDB implements standard row-level locking where there are two types
of locks, shared (S) locks and exclusive (X) locks。

A shared (S) lock permits the transaction that holds the lock to read
a row.

An exclusive (X) lock permits the transaction that holds the lock to
update or delete a row.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

这段话明确说名了共享锁/排他锁都只是行锁,与间隙锁无关,这一点很重要,后面还会强调这一点。其中共享锁是一个事务并发读取某一行记录所需要持有的锁,比如select … in share mode;排他锁是一个事务并发更新或删除某一行记录所需要持有的锁,比如select … for update。

不过这里需要重点说明的是,尽管共享锁/排他锁是行锁,与间隙锁无关,但一个事务在请求共享锁/排他锁时,获取到的结果却可能是行锁,也可能是间隙锁,也可能是临键锁,这取决于数据库的隔离级别以及查询的数据是否存在。关于这一点,后面分析场景一和场景二的时候还会提到。

5、意向共享锁/意向排他锁
MySQL的官方文档中有以下描述:

Intention locks are table-level locks that indicate which type of lock
(shared or exclusive) a transaction requires later for a row in a
table。 https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html The
intention locking protocol is as follows:

Before a transaction can acquire a shared lock on a row in a table, it
must first acquire an IS lock or stronger on the table.

Before a transaction can acquire an exclusive lock on a row in a
table, it must first acquire an IX lock on the table.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

说明意向共享锁/意向排他锁属于表锁,且取得意向共享锁/意向排他锁是取得共享锁/排他锁的前置条件。

共享锁/排他锁与意向共享锁/意向排他锁的兼容性关系:

在这里插入图片描述
这里需要重点关注的是IX锁和IX锁是相互兼容的,这是导致上面场景一发生死锁的前置条件,后面会对死锁原因进行详细分析。

6、插入意向锁(IIX)

MySQL的官方文档中有以下重要描述:

An insert intention lock is a type of gap lock set by INSERT
operations prior to row insertion. This lock signals the intent to
insert in such a way that multiple transactions inserting into the
same index gap need not wait for each other if they are not inserting
at the same position within the gap.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html Suppose
that there are index records with values of 4 and 7. Separate
transactions that attempt to insert values of 5 and 6, respectively,
each lock the gap between 4 and 7 with insert intention locks prior to
obtaining the exclusive lock on the inserted row, but do not block
each other because the rows are nonconflicting.
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

表明尽管插入意向锁是一种特殊的间隙锁,但不同于间隙锁的是,该锁只用于并发插入操作。如果说间隙锁锁住的是一个区间,那么插入意向锁锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。与间隙锁的另一个非常重要的差别是:尽管插入意向锁也属于间隙锁,但两个事务却不能在同一时间内一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)。这里我们再回顾一下共享锁和排他锁:共享锁用于读取操作,而排他锁是用于更新或删除操作。也就是说插入意向锁、共享锁和排他锁涵盖了常用的增删改查四个动作。

7、自增锁
在MySQL的官方文档中有以下描述:

An AUTO-INC lock is a special table-level lock taken by transactions
inserting into tables with AUTO_INCREMENT columns.The
innodb_autoinc_lock_mode configuration option controls the algorithm
used for auto-increment locking.
https://blog.csdn.net/Saintyyu/article/details/91269087 It allows you
to choose how to trade off between predictable sequences of
auto-increment values and maximum concurrency for insert operations.
https://blog.csdn.net/Saintyyu/article/details/91269087

这段话表明自增锁是一种特殊的表级锁,主要用于事务中插入自增字段,也就是我们最常用的自增主键id。通过innodb_autoinc_lock_mode参数可以设置自增主键的生成策略。为了便于介绍innodb_autoinc_lock_mode参数,我们先将需要用到自增锁的Insert语句进行分类:

1)Insert语句分类

1.“INSERT-like” statements(类INSERT语句) (这种语句实际上包含了下面的2、3、4)

所有可以向表中增加行的语句,包括INSERT, INSERT … SELECT, REPLACE, REPLACE … SELECT, and LOAD DATA。包括“simple-inserts”, “bulk-inserts”, and “mixed-mode” inserts.

  1. “Simple inserts”
    可以预先确定要插入的行数(当语句被初始处理时)的语句。这包括没有嵌套子查询的单行和多行INSERT和REPLACE语句,但不包括INSERT … ON DUPLICATE KEY UPDATE。

  2. “Bulk inserts”
    事先不知道要插入的行数(和所需自动递增值的数量)的语句。这包括INSERT … SELECT,REPLACE … SELECT和LOAD DATA语句,但不包括纯INSERT。InnoDB在处理每行时一次为AUTO_INCREMENT列分配一个新值。

  3. “Mixed-mode inserts”
    这些是“Simple inserts”语句但是指定一些(但不是全部)新行的自动递增值。示例如下,其中c1是表t1的AUTO_INCREMENT列:
    INSERT INTO t1 (c1,c2) VALUES (1,‘a’), (NULL,‘b’), (5,‘c’), (NULL,‘d’);
    另一种类型的“Mixed-mode inserts”是INSERT … ON DUPLICATE KEY UPDATE,其在最坏的情况下实际上是INSERT语句随后又跟了一个UPDATE,其中AUTO_INCREMENT列的分配值不一定会在 UPDATE 阶段使用。

2)InnoDB AUTO_INCREMENT锁定模式分类

1.innodb_autoinc_lock_mode = 0 (“traditional” lock mode)
这种锁定模式提供了在MySQL 5.1中引入innodb_autoinc_lock_mode配置参数之前存在的相同行为。传统的锁定模式选项用于向后兼容性,性能测试以及解决“Mixed-mode inserts”的问题,因为语义上可能存在差异。

在此锁定模式下,所有“INSERT-like”语句获得一个特殊的表级AUTO-INC锁,用于插入具有AUTO_INCREMENT列的表。此锁定通常保持到语句结束(不是事务结束),以确保为给定的INSERT语句序列以可预测和可重复的顺序分配自动递增值,并确保自动递增由任何给定语句分配的值是连续的。

在基于语句复制(statement-based replication)的情况下,这意味着当在从服务器上复制SQL语句时,自动增量列使用与主服务器上相同的值。多个INSERT语句的执行结果是确定性的,SLAVE再现与MASTER相同的数据(反之,如果由多个INSERT语句生成的自动递增值交错,则两个并发INSERT语句的结果将是不确定的,并且不能使用基于语句的复制可靠地传播到从属服务器)。

2.innodb_autoinc_lock_mode = 1 (“consecutive” lock mode)

这是默认的锁定模式。在这个模式下,“bulk inserts”仍然使用AUTO-INC表级锁,并保持到语句结束.这适用于所有INSERT … SELECT,REPLACE … SELECT和LOAD DATA语句。同一时刻只有一个语句可以持有AUTO-INC锁。

而“Simple inserts”(要插入的行数事先已知)通过在mutex(轻量锁)的控制下获得所需数量的自动递增值来避免表级AUTO-INC锁, 它只在分配过程的持续时间内保持,而不是直到语句完成。不使用表级AUTO-INC锁,除非AUTO-INC锁由另一个事务保持。如果另一个事务保持AUTO-INC锁,则“简单插入”等待AUTO-INC锁,如同它是一个“批量插入”。

此锁定模式确保,当行数不预先知道的INSERT存在时(并且自动递增值在语句过程执行中分配)由任何“类INSERT”语句分配的所有自动递增值是连续的,并且对于基于语句的复制(statement-based replication)操作是安全的。

这种锁定模式显著地提高了可扩展性,并且保证了对于基于语句的复制(statement-based replication)的安全性。此外,与“传统”锁定模式一样,由任何给定语句分配的自动递增数字是连续的。与使用自动递增的任何语句的“传统”模式相比,语义没有变化,但有个特殊场景需要注意:The exception is for “mixed-mode inserts”, where the user provides explicit values for an AUTO_INCREMENT column for some, but not all, rows in a multiple-row “simple insert”. For such inserts, InnoDB allocates more auto-increment values than the number of rows to be inserted. However, all values automatically assigned are consecutively generated (and thus higher than) the auto-increment value generated by the most recently executed previous statement. “Excess” numbers are lost.

也就说对于混合模式的插入,可能会有部分多余自增值丢失。

在连续锁定模式下,InnoDB可以避免为“Simple inserts”语句使用表级AUTO-INC锁,其中行数是预先已知的,并且仍然保留基于语句的复制的确定性执行和安全性。

3.innodb_autoinc_lock_mode = 2 (“interleaved” lock mode)

在这种锁定模式下,所有类INSERT(“INSERT-like” )语句都不会使用表级AUTO-INC lock,并且可以同时执行多个语句。这是最快和最可扩展的锁定模式,但是当使用基于语句的复制或恢复方案时,从二进制日志重播SQL语句时,这是不安全的。

在此锁定模式下,自动递增值保证在所有并发执行的“类INSERT”语句中是唯一且单调递增的。但是,由于多个语句可以同时生成数字(即,跨语句交叉编号),为任何给定语句插入的行生成的值可能不是连续的。

如果执行的语句是“simple inserts”,其中要插入的行数已提前知道,则除了“混合模式插入”之外,为单个语句生成的数字不会有间隙。然而,当执行“批量插入”时,在由任何给定语句分配的自动递增值中可能存在间隙。

如果不使用二进制日志作为恢复或复制的一部分来重放SQL语句,则可以使用interleaved lock模式来消除所有使用表级AUTO-INC锁,以实现更大的并发性和性能,其代价是由于并发的语句交错执行,同一语句生成的AUTO-INCREMENT值可能会产生GAP。

4.innodb_autoinc_lock_mode参数的修改

vim /etc/my.cnf
innodb_autoinc_lock_mode=2

直接通过命令修改会报错:

set global innodb_autoinc_lock_mode=2;
ERROR 1238 (HY000): Variable 'innodb_autoinc_lock_mode' is a read only variable

3)InnoDB AUTO_INCREMENT锁定模式含义

1.在复制环节中使用自增列
mysql主从复制有三种模式:row,statement,mixed三种。

row模式:

在row模式下,日志中会记录成每一行数据被修改的形式,然后在slave端再对相同的数据进行修改,只记录要修改的数据,只有value,不会有sql多表关联的情况。由于row模式是直接将主库中的每一行数据在从库进行复写,因而row模式的优点是不会存在主从不一致的问题;而row模式的缺点就是会产生大量的binlog日志。

statement模式:

在statement模式下,每一条会修改数据的sql都会记录到master的binlog中,slave在复制的时候sql进程会解析成和原来master端执行多相同的sql再执行。statement模式的优点是不需要记录每一行数据的变化减少了binlog日志量,节省了I/O以及存储资源,提高性能,因为他只需要记录在master上所执行的语句的细节以及执行语句的上下文信息;statement模式的缺点是,由于他是记录的执行语句,所以,为了让这些语句在slave端也能正确执行,那么他还必须记录每条语句在执行的时候的一些相关信息,也就是上下文信息,以保证所有语句在slave端被执行的时候能够得到和在master端执行时候相同的结果。另外就是,由于mysql现在发展比较快,很多的新功能不断的加入,使mysql的复制遇到了不小的挑战,自然复制的时候涉及到越复杂的内容,bug也就越容易出现。在statement中,目前已经发现不少情况会造成Mysql的复制出现问题,主要是修改数据的时候使用了某些特定的函数或者功能的时候会出现,比如:sleep()函数在有些版本中就不能被正确复制,在存储过程中使用了last_insert_id()函数,可能会使slave和master上得到不一致的id等等。由于row是基于每一行来记录的变化,所以不会出现,类似的问题。

mixed模式:

从官方文档中看到,之前的 MySQL 一直都只有基于 statement 的复制模式,直到 5.1.5 版本的 MySQL 才开始支持 row 复制。从 5.0 开始,MySQL 的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给 MySQL Replication 又带来了更大的新挑战。另外,看到官方文档说,从 5.1.8 版本开始,MySQL 提供了除 Statement 和 Row 之外的第三种复制模式:Mixed,实际上就是前两种模式的结合。在 Mixed 模式下,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式,也就是在 statement 和 row 之间选择一种。新版本中的 statment 还是和以前一样,仅仅记录执行的语句。而新版本的 MySQL 中对 row 模式也被做了优化,并不是所有的修改都会以 row 模式来记录,比如遇到表结构变更的时候就会以 statement 模式来记录,如果 SQL 语句确实就是 update 或者 delete 等修改数据的语句,那么还是会记录所有行的变更。

由此可知,如果你在使用基于语句的复制(statement-based replication)请将innodb_autoinc_lock_mode设置为0或1,并在主从上使用相同的值。如果使用innodb_autoinc_lock_mode = 2(“interleaved”)或主从不使用相同的锁定模式的配置,自动递增值不能保证在从机上与主机上相同。

如果使用基于行的或混合模式的复制,则所有自动增量锁定模式都是安全的,因为基于行的复制对SQL语句的执行顺序不敏感(混合模式会在遇到不安全的语句是使用基于行的复制模式)。

  1. “Lost” auto-increment values and sequence gaps

在所有锁定模式(0,1和2)中,如果生成自动递增值的事务回滚,那些自动递增值将“丢失”。一旦为自动增量列生成了值,无论是否完成“类似INSERT”语句以及包含事务是否回滚,都不能回滚。这种丢失的值不被重用。因此,存储在表的AUTO_INCREMENT列中的值可能存在间隙。

  1. Specifying NULL or 0 for the AUTO_INCREMENT column

在所有锁定模式(0,1和2)中,如果用户在INSERT中为AUTO_INCREMENT列指定NULL或0,InnoDB会将该行视为未指定值,并为其生成新值。

  1. 为AUTO_INCREMENT列分配一个负值
    在所有锁定模式(0,1和2)中,如果您为AUTO_INCREMENT列分配了一个负值,则InnoDB会将该行为视为未指定值,并为其生成新值。

  2. 如果AUTO_INCREMENT值大于指定整数类型的最大整数
    在所有锁定模式(0,1和2)中,如果值大于可以存储在指定整数类型中的最大整数,则InnoDB会将该值设置为指定类型所允许的最大值。

  3. Gaps in auto-increment values for “bulk inserts”
    当innodb_autoinc_lock_mode设置为0(“traditional”)或1(“consecutive”)时,任何给定语句生成的自动递增值是连续的,没有间隙,因为表级AUTO-INC锁会持续到 语句结束,并且一次只能执行一个这样的语句。

当innodb_autoinc_lock_mode设置为2(“interleaved”)时,在“bulk inserts”生成的自动递增值中可能存在间隙,但只有在并发执行“INSERT-Like”语句时才会产生这种情况。

对于锁定模式1或2,在连续语句之间可能出现间隙,因为对于批量插入,每个语句所需的自动递增值的确切数目可能不为人所知,并且可能进行过度估计。

  1. 由“mixed-mode inserts”分配的自动递增值

考虑一下场景,在“mixed-mode insert”中,其中一个“simple insert”语句指定了一些(但不是全部)行的AUTO-INCREMENT值。这样的语句在锁模式0,1和2中表现不同。innodb_autoinc_lock_mode=0时,auto-increment值一次只分配一个,而不是在开始时全部分配。当innodb_autoinc_lock_mode=1时,不同于innodb_autoinc_lock_mode=0时的情况,因为auto-increment值在语句一开始就分配了,但实际可能使用不完。当innodb_autoinc_lock_mode=2时,取决于并发语句的执行顺序。

  1. 在INSERT语句序列的中间修改AUTO_INCREMENT列值

在所有锁定模式(0,1和2)中,在INSERT语句序列中间修改AUTO_INCREMENT列值可能会导致duplicate key错误。
4)InnoDB AUTO_INCREMENT计数器初始化

如果你为一个Innodb表创建了一个AUTO_INCREMENT列,则InnoDB数据字典中的表句柄包含一个称为自动递增计数器的特殊计数器,用于为列分配新值。此计数器仅存在于内存中,而不存储在磁盘上。

要在服务器重新启动后初始化自动递增计数器,InnoDB将在首次插入行到包含AUTO_INCREMENT列的表时执行以下语句的等效语句。
SELECT MAX(ai_col) FROM table_name FOR UPDATE;

InnoDB增加语句检索的值,并将其分配给表和表的自动递增计数器。默认情况下,值增加1。此默认值可以由auto_increment_increment配置设置覆盖。

如果表为空,InnoDB使用值1。此默认值可以由auto_increment_offset配置设置覆盖。

如果在自动递增计数器初始化前使用SHOW TABLE STATUS语句查看表, InnoDB将初始化计数器值,但不会递增该值。这个值会储存起来以备之后的插入语句使用。这个初始化过程使用了一个普通的排它锁来读取表中自增列的最大值。InnoDB遵循相同的过程来初始化新创建的表的自动递增计数器。

在自动递增计数器初始化之后,如果您未明确指定AUTO_INCREMENT列的值,InnoDB会递增计数器并将新值分配给该列。如果插入显式指定列值的行,并且该值大于当前计数器值,则将计数器设置为指定的列值。

只要服务器运行,InnoDB就使用内存中自动递增计数器。当服务器停止并重新启动时,InnoDB会重新初始化每个表的计数器,以便对表进行第一次INSERT,如前所述。

服务器重新启动还会取消CREATE TABLE和ALTER TABLE语句中的AUTO_INCREMENT = N表选项的效果(可在建表时可用“AUTO_INCREMENT=n”选项来指定一个自增的初始值,也可用alter table table_name AUTO_INCREMENT=n命令来重设自增的起始值)。

8、空间索引

从 MySQL5.7 开始MySQL整合了boost.geometry库以更好的支持空间数据类型,并支持在在Spatial数据类型的列上构建索引,在InnoDB内,这个索引和普通的索引有所不同,基于R-TREE的结构,目前支持对2D数据的描述,暂不支持3D.

R-TREE和BTREE不同,它能够描述多维空间,而多维数据并没有明确的数据顺序,因此无法在RR隔离级别下构建NEXT-KEY锁以避免幻读,因此InnoDB使用称为Predicate Lock的锁模式来加锁,会锁住一块查询用到的被称为MBR(minimum boundingrectangle/box)的数据区域。因此这个锁不是锁到某个具体的记录之上的,可以理解为一种Page级别的锁。

Predicate Lock和普通的记录锁或者表锁存储在不同的lock hash中,其相互之间不会产生冲突。

更多精彩内容欢迎关注微信公众号
在这里插入图片描述



这篇关于MySQL 8.0 常见锁介绍(一)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程