也正是行锁与表锁的水保,会将手提式有线话机号插入到user表里登记用户

id会变成3,意向锁就是InnoDB使用的表级锁

在档次中日常会有那种供给,用户通过第二方系统登录时假设未有注册,则自动给用户注册,注册过的用户自动登录。有时候图省事或许就平昔INSERT INTO user ON DUPLICAET KEY UPDATE...一句
SQL
化解了,功效都平时,难题就是只要用户表中有auto_increment字段,则会招致auto_increment字段发生空洞难点,1段时间后会发现用户ID会平日出现不总是的气象,固然mysql的自增ID可以极大,一般系统是够用的,然而对于失眠病人那几个是心有余而力不足承受的。小编测试的mysql版本为五.5.58,使用的是Innodb引擎,隔开级别为Repeatable
Read。

1.Locking

1 场景

当用户从第一方登录时,假定用的是手提式有线电话机号做唯1标识,平常在大家通力合作的系统中会建七个用户表,如下:

 CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `mobile` varchar(11) DEFAULT NULL,
  `last_login_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mobile` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

当用户从第三方登录时,大家校验通过后,会将手机号插入到user表里登记用户。借使用户已经存在,则更新最终登录时间,为了方便,平常像下边这么做,成效上看起来是没有错的,难题不怕运维一段时间后会发现user表的id字段居然是不总是的,而且常常八个id之间空洞还极大,比如上二个id是四,下一个改为了2壹。如上面例子中,再插入一条新记录时,id会变成三,也正是说id=二这些值被荒废了。

mysql> INSERT INTO user(mobile, last_login_time) VALUES('15012345678',
 NOW()) ON DUPLICATE KEY UPDATE last_login_time = NOW();
Query OK, 1 row affected (0.00 sec)

mysql> show create table user;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                               |
+----------------------------------------------------------------------+
| user  | CREATE TABLE `user` (
......
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 |

mysql> INSERT INTO user(mobile, last_login_time) VALUES('15012345678', 
NOW()) ON DUPLICATE KEY UPDATE last_login_time = NOW();
Query OK, 2 rows affected (0.00 sec)

mysql> show create table user;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                               |
+-------+---------------------------------------------------------------------
| user  | CREATE TABLE `user` (
......
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 |

一.壹加锁格局:共享锁与独占锁

InnoDB实现了两类行级锁, shared(S)locks 和exclusive(X)locks

  • 共享锁用于工作读取
  • 独占锁用于工作更新或许去除
  • S锁与S锁不争论,与X锁争辩;X锁与S锁争执,与X锁顶牛

2 分析

在MySQL官方文书档案已经涉嫌过那个题材了事实上,当表t第11中学列a已经有三个值为一的情状下,常常景况实施上边那两条语句效果是千篇1律的,可是注意了,假如表t1是InnoDB引擎而且有一列为auto_increment的意况下,影响是不均等的,会时有爆发方今提到的auto_increment空洞难点。MyISAM引擎的表不受此影响,不会发出空洞难点。

INSERT INTO t1 (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=c+1;

UPDATE t1 SET c=c+1 WHERE a=1;

尤为确切的说,发生空洞难点还跟innodb_autoinc_lock_mode那些MySQL配置相关。该配置在MySQL五.一引入,是为了提高auto_increment字段的出现质量引入的,私下认可值为1。该值可以配备为0(traditional lock mode),1(consecutive lock mode),2(interleaved lock mode),除了0基本不发生空洞外,配置别的值都以可能有auto_increment空洞的,容易计算如下,更详尽的能够参考
innodb-auto-increment-handling

  • 一)要是事情回滚了,则无论是0,一,二都会促成事情中选拔过的auto_increment的值浪费。

  • 二)如若设置为0,是traditional lock mode,则任意插入语句都会加
    AUTO-INC 锁,基本不会时有产生空洞,除了第11中学的rollback情形外。

  • 三)借使设置为壹仍然2的时候,simple inserts言语(simple
    inserts指的是这种能够优先分明插入行数的话语,比如INSE奥迪Q5T/REPLACE INTO
    等插入单行或然多行的语句,语句中不包涵嵌套子查询)不会有空洞。但是对于bulk inserts(bulk
    inserts指的是先行不只怕明确插入行数的讲话,比如INSERubiconT/REPLACE INTO …
    SELECT FROM…, LOAD DATA等)和mixed-mode inserts(指的是simple
    inserts类型中有个别行内定了auto_increment列的值多少未有点名,比如:INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d')INSERT ... ON DUPLICATE KEY UPDATE那种话语)会预先分配auto_increment值,导致一些荒废。
    尤其是安装为贰的时候,在进行任意插入语句都不会加 AUTO-INC
    锁,从而在言辞执行进度中都可能产生空洞。

壹.2加锁粒度:意向锁

InnoDB帮助多粒度锁,也等于行锁与表锁的并存。意向锁正是InnoDB使用的表级锁,注脚了政工之后对于这些表所要求行级锁的门类(S|X)。因而意向锁也分为Intention
shared(IS)和Intention exclusive(IX)。

For
example,SELECT ... LOCK IN SHARE MODE
sets an IS lock and
SELECT ... FOR UPDATE
sets an IX lock.

反过来说,在赢得S|X锁在此以前,需求取得相应的IS(或IX)|IX锁。
而那些锁的相容表如下:

X IX S IS
X Conflict Conflict Conflict Conflict
IX Conflict Compatible Conflict Compatible
S Conflict Conflict Compatible Compatible
IS Conflict Compatible Compatible Compatible

三 一种错误示范

这为了收缩第1节中的auto_increment空洞难题,1种办法正是INSE哈弗T前先判断下用户是还是不是存在,不存在才实施插入语句,不然用户每回登录都会造成auto_increment值被浪费。方案如下:

with transaction:
    user = SELECT * FROM user WHERE mobile = '15012345678' FOR UPDATE;
    if not user:
       INSERT INTO user(mobile, last_login_time) VALUES('15012345678', NOW()) 
    UPDATE user SET last_login_time = NOW();

那一个代码乍看是未有失常态了,mobile是unique
key,那样的FOR UPDATE仿佛木非常,那是2个排他锁,1个session对那条记下加了排他锁,别的session不能对那条记下加锁和改动(不能LOCK IN SHARE MODE 以及 UPDATE
等,要注意下SELECT FOR UPDATE只在工作中要么autocommit关闭的气象下才会加锁)。不过,那只在笔录存在的景观下才是对记录加X锁,未有Gap锁。而只要这几个记录不设有,则对第一个不知足条件的记录加Gap锁,有限支撑未有知足条件的笔录插入。

如果mobile=15012345678那条记下不存在,并发的四个session都得以进来SELECT ... FOR UPDATE,因为都以加的Gap锁(X
locks gap before
rec),Gap锁之间是卓殊的。此时,在那之中任意一个session再履行
INSERT INTO user(mobile, last_login_time) VALUES('15012345678', NOW())语句会因为加insert intention lock(注:插入意向锁是壹种特有的Gap锁,不是MySQL的表级意向锁IS,IX等)超时而执行破产。其实此时的Gap锁不只是锁住了
1501234567八 那条记下,假设表中有其余的笔录,会将可能插入 1501234567八的区间都锁住,MySQL加锁详细分析能够见参考资料5。

一.三加锁类型

四 解决方案

为此,若是要优化auto_increment的荒废难点,又要制止上1节提到的死锁难题,依然有个别事情要做的。可行的三种格局如下:

  • 抑或便是干脆一点,在查询用户是还是不是存在时平素用GET_LOCK(mobile),通过字符串锁而不是FOR UPDATE来制止上1节提到的题材。
  • 抑或正是先不加FOR UPDATE询问1遍用户表,假若用户不设有,然后再INSERT IGNORE INTO user ...。多一遍查询,后边的逻辑不变。
  • 当然,percona的那篇小说avoiding-auto-increment-holes-on-innodb-with-insert-ignore还有个很tricky的不二等秘书籍来防止auto_increment的肤浅难题,有趣味的能够参考。

MySQL Innodb固然现身了壹些加锁难题,能够通过上面那些指令来增加援救分析。

show engine innodb status;
select * from information_schema.innodb_locks;
select * from information_schema.innodb_lock_waits;
select * from information_schema.innodb_trx;

Record Lock

Record
lock是在目录项上的锁,例如上边包车型客车SQL会将装有c壹=10的行全部锁住,无法insert、update、delete

SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;

对于从未索引的表,InnoDB也会创制3个藏身的聚簇索引。

READ COMMITTED只有Record Lock没有Gap Lock和Next-key Lock,所以locking
read(即LOCK IN SHARE MODEFOR UPDATE)、UPDATE和DELETE用的都以Record
Lock
REPEATABLE READ则有Record Lock、Gap Lock和Next-key Lock

InnoDB使用行级锁时,是当它寻找或扫描贰个表的目录,在它碰到的十一分索引记录上助长共享或独占锁,所以InnoDB的行级锁实际上便是索引记录锁(Record
Lock)。

https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html\#innodb-record-locks
https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html\#isolevel\_read-committed

伍 参考资料

Gap Lock

Gap
Lock是将索引记录之间的范围加锁的锁,索引值在那段范围内的记录无法insert,如下SQL将锁住10<=c一<=20

SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;

Gap
Lock能够是一段索引值、单个索引值恐怕空,这是在性质和并发度之间权衡的结果,所以唯有部分业务隔断等级使用了。
Gap
Lock在运用唯一索引查询单行结果的时候并不会被用到,但当这几个唯一索引是联合署名索引,并且询问条件只囊括了一部分索引列的时候依然会被使用的。例如下边包车型大巴SQL只会使用2个Record
Lock,假若id有唯一索引的话,并不影响从前索引值上的插入。

SELECT  *  FROM child WHERE id =  100;

当id没有索引,也许不是绝无仅有索引的时候,那么索引值此前的到上1个索引值之间的限定也会被锁。
Gap Lock只会堵住在那个gap范围内的插入操作,所以Gap X-Lock与Gap
S-Lock的功能是同样的,并不会抵触。
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html\#innodb-gap-locks

Next-key Lock

Next-key Lock是在某1个目录记录上的Record
Lock和那几个目录记录在此以前的这段范围的Gap Lock的组成。
就此假使Session A拥有3个索引记录奥迪Q7上的共享|独占Next-key Lock,Session
B就不可能在中华V此前的那段索引记录范围内插入新的目录记录。
譬如3个目录拥有10、1一、一三、20多少个值,那么只怕的Next-key
Lock就包蕴了如下的距离

(-infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, infinity)

InnoDB的暗中认可事务隔绝级别是REPETABLE READ,InnoDB使用Next-key
Lock来搜寻和扫描索引,可以制止Phantom Rows。
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html\#innodb-next-key-locks
https://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html

Insert Intention Lock

Insert Intention
Lock是insert操作在插入行(获取该行的X锁)在此之前使用的壹种Gap
Lock,五个Session假若要插入同2个Gap,但万壹是见仁见智的目录地方那么是不会抵触的。
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html\#innodb-insert-intention-locks

AUTO-INC Lock

AUTO-INC Lock是事情往有Auto
Increment字段的表插入记录时行使的一种表级锁,八个插入的作业必要等待来确定保证主键值的一连性。
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html\#innodb-auto-inc-locks
https://dev.mysql.com/doc/refman/5.7/en/innodb-auto-increment-handling.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html\#sysvar\_innodb\_autoinc\_lock\_mode

2.Transaction Model

多版本(multi-versioning)数据库与两品级加锁(two-phase
locking)的三结合。默许是行级锁以及无锁的1致性读(nonlocking consistent
reads)。

2.1Transaction Isolation Levels

隔开性是数据库在面对五个工作同时进行修改恐怕查询时,调节品质、可相信性、一致性以及结果的可重现性的平衡的要紧。
共有如下四个级别:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

InnoDB默认是REPEATABLE READ

REPEATABLE READ

  1. 同一个事务全体的Consistent
    reads(也正是暗中同意情状,也正是不加锁)使用本事务第二回读时创造的快速照相,也正是说同2个政工中的各类SELECT相互具有壹致性(也正是可重复读,不会合到同时发生的别的事情对于数据的改动)。
  2. Locking reads(SELECT WITH FO帕杰罗 UPDATE O君越 LOCK IN SHARE
    MODE),UPDATE,DELETE语句,会依照语句是还是不是在唯一索引上使用唯壹的规则而选拔不一致的锁。

    • 唯一索引上的绝无仅有准绳,InnoDB会利用Record Lock把这么些index
      Record锁住,而不是Gap Lock。
    • 别的的场合下,InnoDB会利用Gap Lock或Next-Key
      Lock将围观的目录范围给锁住,以阻止其余Session在那段范围插入记录。

READ COMMITTED

  1. 每一个Consistent
    read,就算是在同三个事务中,都会重设读取最新的快速照相(所以会冒出不可重复读的难点)。
  2. Locking reads,UPDATE,DELETE语句,InnoDB只会动用Record
    Lock锁住那些索引值,不会锁住Gap,也正是同意锁住的笔录周边的值的插入(会有幻读的题材),Gap
    Locking只会在外键检查和重复键检查中应用。
  • 对此UPDATE、DELETE语句,InnoDB只会维持它供给更新或删除的行的锁,对于并不包容的行的Record
    Locks,会在MySQL总计完WHERE语句后放走。
  • 对此1个UPDATE语句,假如三个行已经被锁,InnoDB使用一个半1致性读(semi-consistent
    read),重返最新提交到MySQL的数额版本,假诺那些行相配UPDATE的WHERE字句,那么MySQL会重读那些行,并加锁可能等待锁。

READ UNCOMMITTED

SELECT语句不会加锁,恐怕会读到三个行稍早的数码版本,由此在那些级别上,读是不平等的。也正是脏读。其余方面这一个级别和READ
COMMITTED是类似的。

SERIALIZABLE

其超级别类似于REPEATABLE READ

  • autocommit disabled,InnoDB会隐性地把具有SELECT转换为SELECT IN SHARE
    MODE
  • antocommit enabled,SELECT便是和谐的事体

2.2autocommit、commit、rollback

在InnoDB,全体的用户活动都发出在事情中,借使autocommit开启了,各种SQL语句都会协调组合一个作业,MySQL默许为种种Session开启autocommit,所以各类SQL语句执行完并从未出错的话,MySQL都会实施二回commit。假如语句再次来到错误,那么会依照错误执行commit\rollback。

  1. 对此开启了autocommit的Session,可以因此START TRANSACTION或者BEGIN语句来打开一个多语句的工作,然后通过COMMITROLLBACK来结束工作。
  2. 借使autocommit关闭了,那么session永远地处多少个开启的事体中,贰个COMMITROLLBACK语句会结束如今的作业然后打开新的业务。(如果session结束时未尝显式地付出最终的事务,那么MySQL会回滚)

或多或少语句会隐式地付出业务。
一个COMMIT言辞申明当前作业的修改已经持久化,并且对别的session可知;而二个ROLLBACK言语撤废了现阶段政工做的富有修改。COMMIT与ROLLBACK会释放具有当前工作的InnoDB锁。

2.3Consistent nonblocking read

snapshot

某一个一定时间的数据表示,尽管其余业务提交了改动也保险不变,特定的隔绝级别使用那么些来贯彻1致性读(consistent
read)。

consistent read

是运用快速照相(snapshot)音信来体现查询结果的2个读操作,也就表示InnoDB使用multi-versioning来展现有个别时刻数据库快速照相的询问结果。这几个查询能看出这一个时刻在此之前交付的作业修改,而不会看到同一时半刻刻其余事情进行的修改,例外是能观察本事务从前交付的改动。要是查询的多少现已被其余业务修改,那么原来数据会通过undo
log的内容来重建(恢复生机)。那几个技能幸免了壹部分锁带来的产出问题。
REPEATABLE
READ级别,snapshot是开始展览本事务第二回读操作时的多寡,唯有工作提交未来才能博取三个新本子的snapshot。
READ COMMITTED级别,snapshot在历次consistent读操作时重设。
Consistent
read是InnoDB在EscortC|CRUISERCRUISER级别处理SELECT语句时的暗许形式,因为consistent
read不会给它访问的表加锁,其他session能够在3个consistent
read操作时自由地修改那些表。
一旦暗中同意的级别上,当您执行1个consistent
read时,InnoDB会给您的工作1个时间点,你的查询看来的数据库正是以此时间点的数据库。即使别的交事务情在那几个时间点之后剔除了1行并付出,你见到的数据库中那一行并不会被删掉,插入与立异也类似。

snapshot状态适用于SELECT语句,而不是DML语句,假如事务A插入或更新了某个行并提交,那么RAV4普拉多级其余别的事务B即便不能通过查询看来这么些转变,但事务B的DELETE/UPDATE语句也是会影响到刚刚提交的这一个行,假如发生了那种气象,那么那个变迁对于当下事务B就会可知,例如:

SELECT  COUNT(c1)  FROM t1 WHERE c1 =  'xyz';  
-- Returns 0: no rows match.  
DELETE  FROM t1 WHERE c1 =  'xyz';  
-- Deletes several rows recently committed by other transaction.  
SELECT  COUNT(c2)  FROM t1 WHERE c2 =  'abc';  
-- Returns 0: no rows match.  
UPDATE t1 SET c2 =  'cba'  WHERE c2 =  'abc';  
-- Affects 10 rows: another txn just committed 10 rows with 'abc' values.  
SELECT  COUNT(c2)  FROM t1 WHERE c2 =  'cba';  
-- Returns 10: this txn can now see the rows it just updated.

你能够因而付出业务来促进时间点。
那也便是所谓的Multi-versioned concurrency control。
下边包车型客车例子中,session A只有在session
B提交了插入操作并且本人也付出以后才能观察B插入的行,因为唯有在A提交之后A的光阴点才能越过B的提交。

             Session A              Session B

           SET autocommit=0;      SET autocommit=0;
time
|          SELECT * FROM t;
|          empty set
|                                 INSERT INTO t VALUES (1, 2);
|
v          SELECT * FROM t;
           empty set
                                  COMMIT;

           SELECT * FROM t;
           empty set

           COMMIT;

           SELECT * FROM t;
           ---------------------
           |    1    |    2    |
           ---------------------

1经您须要每1天看到最新气象的数据库,使用普拉多C级别或然locking read。

Consistent read对于特定DDL语句也不奏效:

  • DROP TABLE,因为MySQL无法利用叁个去除了的表。
  • ALTELANDTABLE,因为这么些语句会生成四个目前复制表,然后删除原表,当你再一次履行3个consistent
    read的时候,新表里的行对于您的snapshot来说是不存在的,所以事务会报错。

2.4Locking Reads

1经你在工作中询问数据,然后开始展览插队或许更新,普通的SELECT语句不能够提供丰硕的敬服,其余事情能够立异恐怕去除你刚好查询的数据行。InnoDB帮助三种locking
reads来提供额外的保安:

  • SELECT…LOCK IN SHARE MODE
    给要读得行上加共享锁,其余的事体能够读那几个行,但唯有您的政工提交之后才能改改它们。固然其余工作修改了这一个行不过未有交给,那么您的询问须求等待那么些事情甘休然后使用新型的值。
  • SELECT…FOR UPDATE
    给行以及相关的目录记录加排他锁,与UPDATE语句看似。其余工作对于这一个行的更新、Locking
    Reads、可能有个别隔离级别下的读都会堵塞。Consistent
    reads会忽视记录上的锁。
    具有被Locking reads设置的锁会在作业提交或回滚的时候释放。

SELECT FOR
UPDATE对于行的加锁只有在autocommit禁止使用的时候使得,能够经过STACRUISERT
TRANSACTION恐怕将autocommit设为0来剥夺。

3.Locks set by different SQL Statements in InnoDB

Locking read、UPDATE、DELETE平时会给处理SQL进程中装有扫描到的Index
Record加上Record
Lock。它并不会在意WHERE语句是还是不是将这几个行排除了。InnoDB不会记住WHERE条件,只明白它扫描过的index范围。加的锁1般的话是Next-key
Lock,同时也会卡住对Record前边的Gap进行扦插的操作。可是,gap
Locking能够被显式地剥夺,事务隔绝等级也会影响所选择的锁。
假若1个查询用了非聚簇索引并且加的Record
Lock也是排它锁,InnoDB也会取出对应的聚簇索引,并在上头加锁。
若果你的口舌未有确切的目录使用,那么MySQL必须扫描整个表来处理语句,那么表中的每1行都会被加锁,也就会卡住其余用户对于这么些表所有的插入,所以给表建立好的目录很重大,避防查询时扫描很多不须求的行。
InnoDB加锁的状态如下:

  • SELECT…FROM是consistent
    read,不加锁除非隔开分离级别设为SELacrosseIALIZABLE。SE卡宴IALIZABLE级别下,查询会给它境遇的目录记录加Next-key
    Lock,可是在利用唯一索引查询唯一的行时只会给索引记录加Record Lock。

  • SELECT…FROM…LOCK IN SHARE
    MODE给它境遇的全部索引记录加共享Next-key
    Lock,但是在应用唯一索引查询唯1的行时只会给索引记录加Record Lock。

  • SELECT…FROM…FO奥迪Q3 UPDATE给它碰到的有所索引记录加排它Next-key
    Lock,可是在接纳唯一索引查询唯1的行时只会给索引记录加Record
    Lock。
    对此查询时遇见的目录记录,SELECT-FO大切诺基-UPDATE会阻塞其余session举办SELECT-IN-SHARE或然某些级别下的读。Consistent
    read会忽视它多少视图上的记录上的具备锁。

  • UPDATE…WHERE…给它蒙受的有着索引记录加排它Next-key
    Lock,但是在接纳唯一索引查询唯一的行时只会给索引记录加Record Lock。

  • 当UPDATE修改了二个聚簇索引记录,那么相关的非聚簇索引记录上的隐式锁会被拿掉。UPDATE操作也会把受到震慑的非聚簇索引记录上的共享锁拿掉,当执行插入新的非聚簇索引记录前再次值扫描只怕插入新的非聚簇索引记录时。

  • DELETE FROM…WHERE…给它境遇的兼具索引记录加排它Next-key
    Lock,可是在利用唯一索引查询唯一的行时只会给索引记录加Record Lock。

  • INSEQX56T会给插入的行加上2个排它锁。这几个锁是三个索引Record
    Lock,不是Next-key Lock(也正是未有Gap
    Lock)并且不会阻止其余业务往插入行在此之前的Gap中插入记录。
    插入行此前,会加①种Insert intention Gap
    Lock,申明打算要插入,那样几个插入同二个Gap的事务尽管不是要插入到同三个职位那就不须求等待。
    假诺产生duplicate key
    error,会加三个共享锁在争执的行上。详见链接里的INSE酷威T
    https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html

  • INSE奥迪Q5T…ON DUPLICATE KEY UPDATE与简单的INSE路虎极光T不一样,当爆发duplicate
    key error产生的时候,会加1个排它锁在需求更新的行上。

  • REPLACE

  • INSE汉兰达T INTO T SELECT…FROM S WHERE…加三个排它index Record
    Lock在每多个要插入到T的行上。详见文书档案。

  • AUTO_INCREMENT 详见文档。

  • LOCK TABLES
    会加表锁,但那是在比InnoDB层更加高的MySQL层加的锁。InnoDB在innodb_table_locks = 1(the
    default) and
    autocommit = 0的情事下能感知到表锁,而MySQL层一直能感知到行锁。

4.Phantom Rows

5.Deadlocks