会将手机号插入到user表里登记用户,也等于行锁与表锁的并存

在档次中经常会有那种要求,用户通过第2方系统登录时假设没有注册,则自动给用户注册,注册过的用户自行登录。有时候图省事或然就一贯INSERT INTO user ON DUPLICAET KEY UPDATE...一句
SQL
解决了,成效都例行,难点就是假如用户表中有auto_increment字段,则会促成auto_increment字段暴发空洞难点,一段时间后会发现用户ID会常常出现不总是的情状,固然mysql的自增ID可以很大,一般系统是够用的,可是对于情感障碍病人那么些是无能为力接受的。小编测试的mysql版本为5.5.58,使用的是Innodb引擎,隔离级别为Repeatable
Read。

1.Locking

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是4,下贰个化为了21。如上边例子中,再插入一条新记录时,id会变成3,相当于说id=2这么些值被荒废了。

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 |

1.1加锁格局:共享锁与独占锁

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

  • 共享锁用于工作读取
  • 独占锁用于工作更新只怕去除
  • S锁与S锁不争持,与X锁冲突;X锁与S锁争执,与X锁争执

2 分析

在MySQL官方文档已经关系过这么些题材了实际上,当表t1中列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配置相关。该配置在MySQL5.1引入,是为着提高auto_increment字段的产出质量引入的,暗许值为1。该值可以布置为0(traditional lock mode),1(consecutive lock mode),2(interleaved lock mode),除了0基本不发出空洞外,配置其他值都以唯恐有auto_increment空洞的,简单总计如下,更详细的可以参考
innodb-auto-increment-handling

  • 1)尽管事情回滚了,则不管是0,1,2都会导致业务中使用过的auto_increment的值浪费。

  • 2)假如设置为0,是traditional lock mode,则任意插入语句都会加
    AUTO-INC 锁,基本不会发生空洞,除了1中的rollback意况外。

  • 3)若是设置为1要么2的时候,simple inserts讲话(simple
    inserts指的是那种可以优先鲜明插入行数的言辞,比如INSELX570T/REPLACE INTO
    等插入单行只怕多行的说话,语句中不包罗嵌套子查询)不会有空洞。不过对于bulk inserts(bulk
    inserts指的是预先不能明确插入行数的言辞,比如INSE本田UR-VT/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值,导致部分浪费。
    特别是安装为2的时候,在实践任意插入语句都不会加 AUTO-INC
    锁,从而在说话执行进程中都或许发生空洞。

1.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

3 一种错误示范

那为了削减第三节中的auto_increment空洞难题,一种方法就是INSEKoleosT前先判断下用户是还是不是留存,不设有才实施插入语句,否则用户每一次登录都会促成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有如木不平常,那是三个排他锁,多少个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锁不只是锁住了
15012345678 那条记下,若是表中有此外的笔录,会将或许插入 15012345678
的间距都锁住,MySQL加锁详细分析能够见参考资料5。

1.3加锁类型

4 化解方案

为此,要是要优化auto_increment的荒废难点,又要幸免上一节提到的死锁难点,照旧有点事情要做的。可行的三种艺术如下:

  • 抑或就是干脆一点,在询问用户是还是不是存在时直接用GET_LOCK(mobile),通过字符串锁而不是FOR UPDATE来避免上一节提到的难题。
  • 或许就是先不加FOR UPDATE查询一遍用户表,若是用户不设有,然后再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会将装有c1=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使用行级锁时,是当它寻找或扫描1个表的目录,在它碰着的非凡索引记录上助长共享或独占锁,所以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

5 参考资料

Gap Lock

Gap
Lock是将索引记录之间的范围加锁的锁,索引值在那段范围内的笔录不能insert,如下SQL将锁住10<=c1<=20

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

Gap
Lock可以是一段索引值、单个索引值大概空,这是在性能和并发度之间权衡的结果,所以只有部分工作隔离等级使用了。
Gap
Lock在利用唯一索引查询单行结果的时候并不会被用到,但当以此唯一索引是共同索引,并且询问条件只囊括了部分索引列的时候照旧会被利用的。例如下边的SQL只会采取1个Record
Lock,假如id有唯一索引的话,并不影响此前索引值上的插入。

SELECT  *  FROM child WHERE id =  100;

当id没有索引,只怕不是唯一索引的时候,那么索引值以前的到上一个索引值之间的限量也会被锁。
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是在某3个目录记录上的Record
Lock和这些目录记录以前的那段范围的Gap Lock的组合。
为此只要Session A拥有1个目录记录宝马X5上的共享|独占Next-key Lock,Session
B就无法在普拉多此前的那段索引记录范围内插入新的目录记录。
比如1个索引拥有⑩ 、1壹 、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假设要插入同三个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)的结缘。暗中同意是行级锁以及无锁的一致性读(nonlocking consistent
reads)。

2.1Transaction Isolation Levels

隔离性是数据库在直面几个业务同时履行修改或许查询时,调节质量、可信性、一致性以及结果的可再现性的平衡的重中之重。
共有如下多个级别:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

InnoDB默认是REPEATABLE READ

REPEATABLE READ

  1. 同一个事务全部的Consistent
    reads(也等于暗中认同情状,约等于不加锁)使用本事务第陆次读时创立的快照,也等于说同三个作业中的各样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,就算是在同1个事情中,都会重设读取最新的快照(所以会产出不足重复读的题材)。
  2. Locking reads,UPDATE,DELETE语句,InnoDB只会动用Record
    Lock锁住这么些索引值,不会锁住Gap,相当于允许锁住的记录附近的值的插入(会有幻读的标题),Gap
    Locking只会在外键检查和重复键检查中采纳。
  • 对于UPDATE、DELETE语句,InnoDB只会维持它要求更新或删除的行的锁,对于并不匹配的行的Record
    Locks,会在MySQL计算完WHERE语句后刑满释放。
  • 对于1个UPDATE语句,若是多少个行已经被锁,InnoDB使用三个半一致性读(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永远地处3个敞开的业务中,1个COMMITROLLBACK语句会停止如今的政工然后打开新的政工。(若是session截至时没有显式地交给最终的工作,那么MySQL会回滚)

好几语句会隐式地交给业务。
一个COMMIT言语申明当前政工的修改已经持久化,并且对其余session可知;而三个ROLLBACK话语裁撤了当下事务做的享有修改。COMMIT与ROLLBACK会释放具有当前政工的InnoDB锁。

2.3Consistent nonblocking read

snapshot

某贰个特定时间的数据表示,纵然别的作业提交了改动也保持不变,特定的隔断级别使用这几个来贯彻一致性读(consistent
read)。

consistent read

是利用快照(snapshot)消息来显示查询结果的一个读操作,也就意味着InnoDB使用multi-versioning来呈现某些时刻数据库快照的查询结果。这么些查询能来看这几个随时之前交付的工作修改,而不会看到同一时半刻刻其他工作举办的修改,例外是能观看本事务从前交付的改动。假诺查询的多少已经被其余事情修改,那么原来数据会通过undo
log的故事情节来重建(苏醒)。那个技术防止了一部分锁带来的面世难题。
REPEATABLE
READ级别,snapshot是展开本事务第壹回读操作时的数码,唯有工作提交之后才能博得一个新本子的snapshot。
READ COMMITTED级别,snapshot在每趟consistent读操作时重设。
Consistent
read是InnoDB在汉兰达C|CRUISERPRADO级别处理SELECT语句时的默许方式,因为consistent
read不会给它访问的表加锁,其他session可以在3个consistent
read操作时自由地修改那一个表。
假如默许的级别上,当您执行1个consistent
read时,InnoDB会给你的事情3个时间点,你的询问看来的数据库就是以此时间点的数据库。若是其他事情在那些时间点之后剔除了一条龙并付出,你见到的数据库中那一行并不会被删掉,插入与创新也近乎。

snapshot状态适用于SELECT语句,而不是DML语句,如若事务A插入或更新了一些行并提交,那么KoleosLacrosse级其余其他事务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    |
           ---------------------

倘诺你须求每日看到最新气象的数据库,使用库罗德C级别只怕locking read。

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

  • DROP TABLE,因为MySQL不能使用三个剔除了的表。
  • ALTE科雷傲TABLE,因为那一个语句会生成二个目前复制表,然后删除原表,当你重新履行五个consistent
    read的时候,新表里的行对于您的snapshot来说是不存在的,所以事务会报错。

2.4Locking Reads

若是您在作业中询问数据,然后进行扦插只怕更新,普通的SELECT语句不能提供丰裕的维护,其余工作可以革新可能去除你碰巧查询的数据行。InnoDB辅助三种locking
reads来提供额外的护卫:

  • SELECT…LOCK IN SHARE MODE
    给要读得行上加共享锁,其余的工作可以读这几个行,但唯有你的作业提交之后才能改改它们。假设别的作业修改了那些行不过没有付诸,那么你的询问需求等待那些事情截止然后使用新型的值。
  • SELECT…FOR UPDATE
    给行以及有关的目录记录加排他锁,与UPDATE语句看似。其余业务对于那些行的换代、Locking
    Reads、或然有些隔离级别下的读都会卡住。Consistent
    reads会忽视记录上的锁。
    具备被Locking reads设置的锁会在工作提交或回滚的时候释放。

SELECT FOR
UPDATE对于行的加锁唯有在autocommit禁用的时候使得,可以经过STA途胜T
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范围。加的锁一般的话是Next-key
Lock,同时也会堵塞对Record前面的Gap举行插队的操作。不过,gap
Locking可以被显式地剥夺,事务隔离等级也会潜移默化所采纳的锁。
如若1个查询用了非聚簇索引并且加的Record
Lock也是排它锁,InnoDB也会取出对应的聚簇索引,并在地方加锁。
即使你的言辞没有确切的目录使用,那么MySQL必须扫描整个表来处理语句,那么表中的每一行都会被加锁,也就会阻塞其余用户对于这么些表全体的插入,所以给表建立好的目录很重大,避防查询时环顾很多不必要的行。
InnoDB加锁的场地如下:

  • SELECT…FROM是consistent
    read,不加锁除非隔离级别设为SE奔驰G级IALIZABLE。SE瑞鹰IALIZABLE级别下,查询会给它蒙受的目录记录加Next-key
    Lock,然则在选取唯一索引查询唯一的行时只会给索引记录加Record Lock。

  • SELECT…FROM…LOCK IN SHARE
    MODE给它蒙受的富有索引记录加共享Next-key
    Lock,可是在运用唯一索引查询唯一的行时只会给索引记录加Record Lock。

  • SELECT…FROM…FO纳瓦拉 UPDATE给它遇到的拥有索引记录加排它Next-key
    Lock,不过在选拔唯一索引查询唯一的行时只会给索引记录加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。

  • INSELacrosseT会给插入的行加上1个排它锁。那么些锁是多个索引Record
    Lock,不是Next-key Lock(相当于没有Gap
    Lock)并且不会阻碍其余业务往插入行以前的Gap中插入记录。
    插入行以前,会加一种Insert intention Gap
    Lock,讲明打算要插入,那样八个插入同一个Gap的工作如若不是要插入到同二个岗位那就不需求拭目以俟。
    若果暴发duplicate key
    error,会加二个共享锁在冲突的行上。详见链接里的INSEMuranoT
    https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html

  • INSERT…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

相关文章