• MySQL锁和事务(一):InnoDB锁(MySQL 官方文档粗翻)


      // 写在前面,实际上,数据库加锁的类型和范围受到多种因素的影响,例如数据库隔离等级,SQL语句,是否使用主键、索引等等。可以查看博文: http://www.cnblogs.com/zhaoyl/p/4121010.html 了解

      这一章节讲述了InnoDB使用的锁类型。

    • 共享锁(S)和独占锁(X)
    • 意向锁
    • 行锁(record lock,不知道叫 记录锁是不是更好,百度了一下有人叫行锁)
    • 间隙锁(gap lock)
    • Next-Key锁
    • 插入意向锁
    • AUTO-INC(自增长)锁
    • 空间锁(Predicate Locks for Spatial Indexes)

     共享锁和独占锁

      InnoDB实现了两种标准的行级锁,一种是共享锁(S锁),一种是独占锁(X锁)。

    • 共享锁允许事务读取一条记录。
    • 独占锁允许事务更新或者删除一条记录的锁。

      如果一个事务 T1 拥有记录 r 的共享锁,另外一个事务 T2 想要对行 r 加锁的请求会得到这样的处理:

    • 如果 T2 想要加一个 S 锁,那么他能马上获得这个锁。结果就是,T1 和 T2 同时拥有 r 的共享锁。
    • T2 想要获取的是 X 锁,那么这么请求会被阻塞。

      如果一个事务 T1 拥有行 r 的 X 锁,另外一个事务 无论想获取 r 的什么锁都会被阻塞。事务 T2 必须要先等待 T1释放 r 上面的S锁。

      意向锁

      InnoDB 支持多粒度的锁,允许行锁和表锁共存。为了支持多粒度的锁,InnoDB引入了意向锁。意向锁是一个表级别的锁,表明一个事务在之后(requires later)要获取表中某些行的S锁或X锁。InnoDB中使用了两种意向锁(假设事务 T 已经向表 t 请求获取对应的意向锁)

    • 意向共享锁(IS):事务 T 想要对表 t 中的一些行加上S锁。
    • 意向排他锁(IX):事务 T 想要对这些行加上X锁。

      例如

    SELECT ... LOCK IN SHARE MODE  

      设置了 IS 锁,而

    SELECT ... FOR UPDATE 

      设置了 IX 锁。

      意向锁协议(The intention locking protocol)如下所示:

    • 在一个事务获取表 t 中某一行的 S锁之前,他必须先获取 IS锁或者一个更重量级的锁(X等)
    • 在一个事务获取一行的 X锁之前,他必须先获取表 t的 IX锁。

      这些规则可以总结为下面的图表(横向表示一个事务已经获取了对应的锁,纵向表示另外一个锁想要获取对应的锁--这段话我自己加的):

      X IX S IS
    X   冲突   冲突   冲突   冲突  
    IX 冲突   不冲突   冲突   不冲突  
    S 冲突   冲突 不冲突   不冲突
    IS 冲突   不冲突 不冲突   不冲突

      当行上的锁与已经存在的锁不冲突(兼容)时,可以被事务请求获取,如果冲突话,就不行。事务必须等待冲突的锁被释放(才能获取想要的锁)。如果一个加锁请求与已存在的锁相互冲突,又一直得不到锁,可能是发生了死锁,或者出现了错误。

      因此,意向锁不会阻塞除全表请求(例如,LOCK TABLES ...WAITE)之外其他请求。IX 和 IS锁的主要目的是表明 某个请求(someone)已经锁定了一行,或者将要锁定一行记录。

      意向锁加锁过程中记录的事务数据类似于下面使用 SHOW ENGINE INNODB STATUS语句的 InnoDB 监控输出:

      

    TABLE LOCK TABLE 'test.'t' trx id 10080 lock mode IX

      

      行锁

      行锁是一个加在索引记录上的锁,例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;会阻止其他任何事务插入,更新或者删除那些 t.c1 = 10的记录。

      行锁总是在索引记录上面加锁,即使一张表没有任何索引,在这种情况下,InnoDB会创建一个隐藏的聚集索引,然后使用这个索引来加上行锁。

      行锁加锁过程中记录的事务数据类似于下面使用 SHOW ENGINE INNODB STATUS语句的 InnoDB 监控输出:

    RECORDS LOCKS space id 58 page no 3 n bits 72 index 'PRIMARY' of table 'test'.'t'
    trx id 10078 lock_mode X locks rec but not gap
    Record lock ,heap on 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
    0: len 4; hex 8000000a; asc  ;;
    1: len 6; hex 00000000274f; asc  'O;;
    2: len 7; hex b60000019d0110; asc  ;;

      间隙锁

      间隙锁是在索引记录的间隙上加的锁,或者在第一条索引记录之前、最后一条索引记录之后的区间上加的锁。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 AND 20 FOR UPDATE; 阻止所有其他的事务 插入一条 t.c1 = 15的记录,无论是否表中已经有一列的值是15(或者其他10-20之间的值),因为在这个范围内的间隙都已经被加上了锁。

      间隙可能只包括一个索引值,也可能包括多个索引值,甚至不包含任何索引值。

      使用唯一索引查找唯一一条记录的语句是不会使用到间隙锁的(这不包括查询条件仅包含一个唯一索引的一部分的语句)。例如,假如 id 列有一个唯一索引,下面的语句只会使用行锁加到 id = 100的行上面,而不会关心别的会话(session)是否在上述的间隙中插入数据。

    SELECT * FROM child WHERE id = 100 ;  (感觉应该加一个 FOR UPDATE 或者 IN SHARE MODE 或者 数据库隔离等级为 serializable)

      如果 id 列没有索引或者不是唯一索引,这个语句会在上述的间隙上加锁。

      值得提醒的是,不同的事务可以在间隙上拥有相互冲突的锁。例如,事务 A 可以某一个间隙上的共享锁(gap S-lock),同时另外一个事务可以在同一个间隙上拥有独占锁(gap  X-lock)。原因在于如果一条索引记录被删除,其他事务拥有的对应间隙锁必须进行归并(强行翻译,不太明白,原文:The reason conflicting gap locks are allowed is that if a record is purged from an index, the gap locks held on the record by different transactions must be merged.)

      间隙锁是 ”完全禁止性的“(强行翻译:purely inhibitive,看下文应该很好理解),意味着他们只会禁止其他的事务插入数据到间隙之中,而不会禁止别的事务获取同一区间的间隙锁。因此,间隙 X锁和间隙 S锁起到的效果是一样的。

      间隙锁可以被明确的禁止。你可以将事务隔离等级设置为 READ COMMITTED 或者启用 innodb_locks_unsafe_for_binlog 系统变量(现在不建议使用 deprecated)。在这些情况下,间隙锁在查询和索引扫描中被禁用,只会在外键约束检查和重复索引检查时才会使用。

      使用READ COMMITTED 隔离等级和 启用innodb_locks_unsafe_for_binlog系统变量也会造成一些额外的影响。在MySQL分析完 WHERE 条件之后,不匹配的行上面的行锁会被释放。对于 UPDATE 语句,InnoDB 进行一个”半一致性“读,它会返回最新提交的版本(的行记录)给MySQL,然后MySQL

      确定哪些行匹配了 UPDATE 的 WHERE 条件。

      

      Next-Key Locks

      next-key 锁是行锁和在行锁之前的间隙上的间隙锁的联合。

      InnoDB以这种形式实现行级锁,当他查找或扫描表索引的时候,遇到匹配的的索引记录,在上面加上对应的共享锁或者独占锁。因此,行级锁实际上是索引记录锁。next-key锁同是会影响索引记录之前的间隙。就是说,next-key lock就是一个索引记录锁加上一个在索引记录之前的间隙上的间隙锁。如果一个会话拥有记录 R 的索引上面的一个共享锁或独占锁,另外的会话无法立即在 R记录索引顺序之前的间隙上插入一条新的记录。

      假设有一个索引包含值10,11,13和20。下列的间隔上都可能加上一个next-key lock,(符号表示不包含端点,]符号表示包含端点。

    (negative infinity ,10]
    (10,11]
    (11,13]
    (13,20]
    (20,positive infinity)

      在最后一个区间中,next-key lock锁定了索引中的最大值到一个“上确界”(一个虚假的索引记录,他的值比所有索引记录中所有值都要大)。上确界不是一个真实存在的索引记录,所以,事实上,这个nex-key lock只是锁定了最大索引值之后的区间。

      默认情况下,InnoDB启用 REPEATABLE READ 事务隔离等级。在这种情况下,InnoDB在查找和扫描索引时会使用 nex-key lock,能避免 幻(影)行的出现。

      next-key lock 加锁过程中记录的事务数据类似于下面使用 SHOW ENGINE INNODB STATUS语句的 InnoDB 监控输出:

      

    RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
    trx id 10080 lock_mode X
    Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
    0: len 8; hex 73757072656d756d; asc supremum;;
    Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
    0: len 4; hex 8000000a; asc ;;
    1: len 6; hex 00000000274f; asc 'O;;
    2: len 7; hex b60000019d0110; asc ;;

      插入意向锁

      插入意向锁

     

      AUTO-INC Locks(自增长锁)

      自增长锁是特殊的表级锁,被那些插入带有AUTO_INCREMENT行的记录到表中时占用。一个最简单的例子,当一个事务在插入数据到表中时,其他任何的事务都等待,因此,第一个事务插入的行能够拥有连续的主键值。

      innodb_autoinc_lock_mode配置选项控制了自增长锁使用的算法。他允许你在可预测的自增长值和最大化并发插入操作之间进行权衡。

      空间索引的断言锁

      InnoDB支持空间列上面的空间索引。

      在处理包括空间索引的相关锁定操作时,next-key locking 在支持 REPEATABLE READ 和 SERIALIZABLE 事务隔离等级 上工作的不太好。在多维的数据上,没有一个绝对的顺序,因此,“下一个”键在哪里并不是很清楚。

      为了支持带有 空间索引的隔离等级,InnoDB使用了断言锁。空间索引包含了 最小外接矩阵(minimum bounding rectangle = MBR)值,所以InnoDB 强制对索引一致性读的时候对查询语句中使用的MBR值上设置一个断言索引。其他的事务不能插入或者修改匹配这个查询条件的行。

      

  • 相关阅读:
    java并发编程——Excutor
    java并发编程——BlockingQueue
    const int *p和int * const p的区别(常量指针与指向常量的指针)
    C语言 enum作为函数返回值及函数参数
    (void)0;
    浅析IAR环境下Flash loader工作原理 (转)
    xilinx zcu106 vcu demo
    flashloader速度提升
    typora--简洁的markdown编辑器
    vivado 2019.2 工程修改文件夹名称后引起的一系列问题
  • 原文地址:https://www.cnblogs.com/mezhouyang/p/7407332.html
Copyright © 2020-2023  润新知