http://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.htmlhtml
前置:检索若是用不到索引,会扫描全表,并根据策略加锁。因此,这就是咱们合理创建索引的原因。mysql
锁定读、Update、Delete,在处理sql过程当中, 通常会在每条扫描过的索引记录上设置记录锁。语句中是否有where条件并无关系(会排除)。InnoDB不会记住实际上的Where条件,但他知道被扫描过的索引范围。使用的锁一般是next-key锁,也会锁住记录以前的“gap”。Next-Key锁不只仅锁住扫描到的合法索引记录,同时会阻塞插入gap间隙中,gap是指上一条合法索引记录到当前扫描到的合法索引记录的开区间。gap锁能够被显示的禁止,致使next-key不会被使用。sql
事物的隔离级别一样会影响使用什么锁。数据库
若是一个二级索引被用来扫描,且索引记录(二级索引,非惟一索引)将要加排他锁,InnoDB会检索相对应的聚簇索引记录,并锁住。并发
聚簇索引(clustered index)
1) 有主键时,根据主键建立聚簇索引
2) 没有主键时,会用一个惟一且不为空的索引列作为主键,成为此表的聚簇索引
3) 若是以上两个都不知足那innodb本身建立一个虚拟的汇集索引
辅助索引(secondary index)
非聚簇索引都是辅助索引,像复合索引、前缀索引、惟一索引高并发
若是没有合适的索引使用,MySQL会扫面整张表,来处理语句,这样表中的每一行都会被锁住(合理创建索引,提升并发效率)。性能
对于 SELECT ... FOR UPDATE
or SELECT ... LOCK IN SHARE MODE,扫描到的行都会锁住,而且指望在有些row不会加入结果集中(例如不知足Where条件)释放这些行的锁。注:其实扫描了全表,只不过在扫描完成以后,判断Where条件时不知足,则会释放锁。
然而对于某些状况下,不会当即释放行锁,由于在查询执行期间一个结果行和他的原始来源之间的关系可能已经丢失,例如Union,从表中扫描行,在计算他们是否加入结果集以前,这些行可能被插入临时表中。此时,临时表中的行和原始表中的行的关系已经丢失,原始表中的行不会解锁知道查询执行完成。spa
InnoDB按照以下设置具体的锁:code
SELECT ... FROM 是一个一致性非锁定读,读取数据库的快照,不会加锁,除非隔离级别为S。对于S隔离级别,检索结果集在索引记录项上使用共享锁且是next-key锁。可是,当惟一肯定记录时,next-key锁会降级为记录锁。
SELECT ... FROM ... LOCK IN SHARE MODE 在检索到的全部索引记录上设置共享锁且是next-key锁。可是,当惟一肯定记录时,next-key锁会降级为记录锁。
SELECT ... FROM ... FOR UPDATE
在检索到的每条记录上的每个记录上加排他锁且是next-key锁。可是,当惟一肯定记录时,next-key锁会降级为记录锁。对索引记录加的排他锁阻塞共享锁和某些隔离级别的操做读。一致性非锁定读,会忽略任何锁。UPDATE ... WHERE ...
在检索到的每条记录上的每个记录上加排他锁且是next-key锁。可是,当惟一肯定记录时,next-key锁会降级为记录锁。DELETE FROM ... WHERE ... 在检索到的每条记录上的每个记录上加排他锁且是next-key锁。可是,当惟一肯定记录时,next-key锁会降级为记录锁。
INSERT 设置一个排它锁在插入的行上,这是一个记录锁,不是next-key,就是说没有gap锁,不会阻止其余事物插入被插记录以前的gap中。
在插入以前,一种叫插入意向锁的gap类型锁,被设置,这个锁表示对事物插入同一个gap中时,不须要相互等待,只要他们不是插入gap中相同的位置。htm
设置插入操做的排他锁以前,现货去gap的插入意向锁,俩个事物能够在同一个gap(重叠也能够)加插入意向锁不会阻塞。
若是有重复冲突,一个共享锁在重复的索引记录上设置。共享锁的使用可能致使死锁:当多个会话插入相同的行时,若是有某个会话已经持有了X锁,此时会致使死锁。举个例子:若是有某个会话删除该行,另外俩个插入行,则会死锁。
Session 1:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 2:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 3:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 1:
ROLLBACK;
上述状况是会话1已经获取了x锁在r行上,会话2和4都会引发重复键冲突,俩个会话都转而去请求r行共享锁,当会话1回滚时,它释放他的排它锁,会话2和3的共享锁请求被授予,此时,会话2和3死锁:没有任何一个会获取排它锁,由于他们都持有了共享锁。
Session 1:
START TRANSACTION; DELETE FROM t1 WHERE i = 1;Session 2:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 3:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 1:
COMMIT;
上述状况和第一种相似。
INSERT ... ON DUPLICATE KEY UPDATE 不一样与简单的Insert,当重复值冲突时,加的锁是一个排它next-key锁而不是一个共享锁-记录锁。
REPLACE 若是在惟一key上没有冲突,像INSERT同样加锁。够则像INSERT ... ON DUPLICATE KEY UPDATE同样
innodb_locks_unsafe_for_binlog
(此时不能是隔离级别S),InnoDB在S表上是一致性非锁定读(不加锁)。不然,InnoDB会设置共享的next-key锁到从S表检索结果中的行。 CREATE TABLE ... SELECT ...
执行 SELECT使用共享的next-key锁,或者一致性非锁定读,就像
INSERT ... SELECT
.同样.
当一个SELECT在相似REPLACE INTO t SELECT ... FROM s WHERE ...
or UPDATE t ... WHERE col IN (SELECT ... FROM s ...)的结果中,InnoDB设置共享且next-key锁在表S上的行上。
LOCK TABLES 设置表级锁