国内外婚纱网站建设现状,服装品牌策划及营销推广方案,设置网站解析,百度权重网站执行锁定读操作#xff08;如 SELECT ... FOR UPDATE/SHARE#xff09;、UPDATE 或 DELETE 通常会对处理 SQL 语句时扫描到的每个索引记录设置记录锁#xff0c;即使 WHERE 条件可能排除了某些行也一样。这些锁通常是下一个键锁(next-key locks)#xff0c;它们… 执行锁定读操作如 SELECT ... FOR UPDATE/SHARE、UPDATE 或 DELETE 通常会对处理 SQL 语句时扫描到的每个索引记录设置记录锁即使 WHERE 条件可能排除了某些行也一样。这些锁通常是下一个键锁(next-key locks)它们还会阻止在记录之前的“间隙”内进行插入。但可以显式禁用间隙锁定从而不使用下一个键锁。事务隔离级别也会影响设置的锁类型。 如果搜索中使用了二级索引并且需要设置的索引记录锁是排他性的InnoDB 还会检索相应的聚簇索引记录并对其设置锁。 如果没有适合语句的索引并且 MySQL 必须扫描整个表来处理语句则整个表的每一行都将被锁定从而阻塞其他用户对该表的所有插入操作。创建良好的索引非常重要以便您的查询不扫描比必要更多的行。 对于锁定读取、UPDATE 和 DELETE 语句根据语句是否使用唯一索引和唯一搜索条件或范围类型搜索条件而采取不同的锁。 对于有唯一搜索条件的唯一索引只锁定找到的索引记录不锁定其前面的间隙。 对于其他搜索条件和非唯一索引会锁定被扫描的索引范围并使用间隙锁或下一个键锁阻止其他会话插入到范围覆盖的间隙中。 对于搜索遇到的索引记录SELECT ... FOR UPDATE 阻止其他会话执行 SELECT ... FOR SHARE 或在某些事务隔离级别下读取。一致读取会忽略在读取视图中存在的记录上设置的任何锁。 UPDATE ... 在搜索遇到的每条记录上设置排他性的下一个键锁。但是使用唯一索引锁定行以搜索唯一行的语句只需要索引记录锁。 当 UPDATE 修改聚簇索引记录时在受影响的二级索引记录上也会隐式地设置锁。在插入新的二级索引记录之前执行重复检查扫描时以及插入新的二级索引记录时操作也会在受影响的二级索引记录上设置共享锁。 DELETE FROM ... 在搜索遇到的每条记录上设置排他性的下一个键锁。但是使用唯一索引锁定行以搜索唯一行的语句只需要索引记录锁。 INSERT 在插入的行上设置排他锁。这个锁是索引记录锁而不是下一个键锁没有间隙锁不会阻止其他会话在插入行之前的间隙中插入。 在插入行之前会设置一种称为插入意向间隙锁的间隙锁。这种锁表示插入的意图多个事务在相同索引间隙中插入时无需等待彼此只要它们不是在间隙中的相同位置插入。 如果发生重复键错误将在重复的索引记录上设置共享锁。如果尝试插入相同行的多个会话与已经拥有排他锁的另一个会话冲突可能会导致死锁。
例如假设有 InnoDB 表 t1其结构如下
CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE InnoDB;
现在假设三个会话按顺序执行以下操作
会话 1
START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话 2
START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话 3
START TRANSACTION; INSERT INTO t1 VALUES(1);
会话 1
ROLLBACK;
会话 1 的第一个操作获得了行的排他锁。会话 2 和 3 的操作都导致重复键错误并且它们都请求行的共享锁。当会话 1 回滚时它释放了对行的排他锁同时授予了会话 2 和 3 的共享锁请求。此时会话 2 和 3 发生死锁由于彼此持有共享锁两者均不能获取行的排他锁。 INSERT ... ON DUPLICATE KEY UPDATE 与普通的 INSERT 不同当发生重复键错误时将对待更新的行放置排他锁而不是共享锁。对于重复的主键值会获得排他的索引记录锁对于重复的唯一键值会获得排他的下一个键锁。 REPLACE 在没有唯一键冲突时像 INSERT 一样执行。否则将在要替换的行上放置一个排他的下一个键锁。 INSERT INTO T SELECT ... FROM S WHERE ... 在插入到 T 的每一行上设置排他索引记录锁没有间隙锁。如果事务隔离级别是 READ COMMITTEDInnoDB 会对 S 进行一致性读取无锁。否则InnoDB 会在 S 的行上设置共享的下一个键锁。 CREATE TABLE ... SELECT ... 使用共享的下一个键锁或作为一致读取来执行 SELECT就像 INSERT ... SELECT。 当使用 SELECT 在 REPLACE INTO t SELECT ... FROM s WHERE ... 或 UPDATE t ... WHERE col IN (SELECT ... FROM s ...) 结构中时InnoDB 会在表 s 的行上设置共享的下一个键锁。 InnoDB 在初始化之前指定的 AUTO_INCREMENT 列的索引末端设置排他锁。
具有 innodb_autoinc_lock_mode0 时InnoDB 使用特殊的 AUTO-INC 表锁模式在访问自增计数器时获取锁并保持至当前 SQL 语句结束。其他客户端不能在持有 AUTO-INC 表锁时向表中插入数据。innodb_autoinc_lock_mode2 不使用表级 AUTO-INC 锁。 具有外键约束的表上的任何插入、更新或删除操作如果需要检查该约束条件则会在它查看的记录上设置共享级别的记录锁。即使约束失败InnoDB 也会设置这些锁。 LOCK TABLES 设置表锁这是在 MySQL 上层而不是 InnoDB 层完成的。如果 innodb_table_locks 1默认设置且 autocommit 0则 InnoDB 会意识到表锁并且 MySQL 上层也会知道行锁。 LOCK TABLES 如果 innodb_table_locks1默认值会在每个表上获取两个锁。除了 MySQL 层的表锁外它还会获取一个 InnoDB 表锁。要避免获取 InnoDB 表锁可以设置 innodb_table_locks0。如果没有获得 InnoDB 表锁那么即使一些表记录正在被其他事务锁定LOCK TABLES 也可以完成。 在事务被提交或中止时所有由事务持有的 InnoDB 锁都会被释放。因此在 autocommit1 模式下对 InnoDB 表使用 LOCK TABLES 没有太大意义因为获得的 InnoDB 表锁将立即被释放。 事务进行过程中不能锁定额外的表