持锁语句
SSELECT
XUPDATE / DELETE 
ISSELECT FOR SHARE
IXSELECT FOR UPDATE



  • SHARED LOCK / EXCLUSIVE LOCK  (row-level)

    共享锁允许事务持有读一行的锁;

    排他锁允许事务持有更新或删除一行的锁。

    如果事务T1持有行r上的共享锁S,那么其他的事务T2获得行r上的锁有如下情况:
      T2可以立即获得共享锁S。
      T2不能立即获得排他锁X。

    如果事务T1持有行r上的排他锁X,T2想在行r上获得任何类型的锁都不会立即得到,必须等待T1释放了行r上的排他锁。


  • INTENTION LOCK  (table-level)

    InnoDB实现多粒度锁机制,允许表锁和行锁的共存。

    InnoDB使用意向锁来实现多粒度锁共存机制。

    意向锁是表级锁,它表明这个事务在接下来将对表中的一行请求什么类型的锁(S/X)。

    • intention shared lock , 表明事务T将要在表t的个别行上加S锁(将要读取某些行);  
      例如 select ... lock in share mode 
    • intention exclusive lock , 表明事务T将要在表t的个别行上加X锁(将要  U/D 某些行)。
      例如 select ... for update  

    意向锁的协议如下:

    • 事务在获得表中一行的S锁之前,它必须首先获得这张表上的IS锁,或更stronger的锁
    • 事务在获得表中一行的X锁之前,它必须首先获得这张表上的IX锁,或更stronger的锁

    锁类型的兼容矩阵列表如下


    XIXSIS
    X××××
    IX××

    S××
    IS×


    当一个事务请求某个类型的锁时,如果这个类型的锁与请求对象上持有的锁相兼容,那么会成功获得请求的锁。

    如果请求的锁与当前请求对象上持有的锁相冲突,那么事务就会等待已存在的锁释放。如果等待的这个锁不可能被授予,就会发生死锁。

    意向锁的主要作用是表明某个事务正在锁住某一行、或将要锁住某一行。 


  • RECORD LOCK

    Record lock是在索引记录上的锁。

    Record locks总是锁住索引记录,即便一个表没有定义索引。这种情况下InnoDB创建隐藏的集簇索引,用这个隐藏的集簇索引来进行record locking。


  • GAP LOCK

    间隙锁是锁在index records之间间隙上的锁,或者第一个index record之前的间隙、最后一个index record之后的间隙。

    例如: SELECT c1 FROM t where c1 BETWEEN 10 and 20  FOR UPDATE ; 这句SQL会阻止其他事务插入c1为15的记录, 

    根据index record的记录来确定间隙锁的范围

    如果10 和 20 都有具体的index record , 那么锁住的范围是10-20 ; 

    如果10 和 20 没有具体的index record , 那么锁住的范围是  10之前的index record  - 20 之后的index record 。

    不管是否有这条记录都会阻止插入,因为这个间隙都被锁住了。

    一个间隙可能跨越一个单一的索引值、多个索引值、甚至是空。

    间隙锁需要综合考虑性能和并发,只在某些事务隔离级别(RR)中才会使用。

    对于使用唯一索引查找唯一行、然后进行锁定的语句来说,不需要间隙锁。

    (如果查询条件只包含唯一索引的部分列,这种情况仍需要间隙锁)。

    例:

    SELECT * FROM child WHERE id = 100 ;

    如果id列是唯一索引,那么上面的语句将只持有id等于100这一行的record lock,并不阻止其他事务插入数据到该条记录前面的间隙中。
    (假设表记录有两条,id为 50 和 100 ,那么这里说的该条记录前面的间隙即表示(50,100] )。

    如果id列上没有索引,或不是唯一索引,那么这条语句会锁住该条记录之前的间隙。

    需要注意的是,不同的事务可以在一个gap上持有冲突的锁。
    例如,当事务B持有排他gap lock(gap X-lock)锁,事务A可以同时持有共享gap lock(gap S-lock) 锁。
    这种情况的原因是因为,如果一条记录从index中被purge时,在这条记录上,当前事务gap锁和其他事务上的gap锁必须被merged。

    Gap lock是抑制性的,这表示gap lock只会阻止其他事务插入新的记录到这个gap中。
    不会阻止其他的事务在相同gap上获取gap locks。因此,gap x-lock 和 gap s-lock的影响是相同的。

    gap lock 可以被显式的禁止。
    在事务级别更改为read committed , 或innodb_locks_unsafe_for_binlog变量(已废弃)被启用的情况下。
    在这种情况,gap locking在查询、索引扫描时会被禁用,只会用来做外键约束检查和重复键检查。


  • NEXT-KEY LOCK 

    next-key lock是一个record lock和这个record lock之前的gap lock的组合。

    InnoDB在查找或浏览表索引的时候,InnoDB会在遇到的每个index record上加S或X锁。

    row-level锁实际上是index-record锁。

    index record上的next-key锁同时会影响这个index record之前的gap。

    如果一个session在记录R上持有S或X锁,另外的session不能立即往R之前的gap中插入新的record。   

    当用到的索引是唯一索引时,不会有gap lock,只会在当前行上加锁。

    假设一个索引包含记录如下: 10,11,13和20。可能有的next-key locks情况如下:
    ( -∞ , 10]
    (10 , 11]
    (11 , 13]
    (13 , 20]
    (20 , +∞)
    PS:(13 , 20] 意为 13 < x <= 20。

    默认情况下,InnoDB操作是在repeatable read事务隔离级别。在这种隔离级别下,InnoDB使用next-key locks来防止产生幻读。


  • INSERT INTENTION LOCK 

    insert intention lock是一种间隙锁,在INSERT操作之前加锁。

    多个事务插入相同index gap时,如果不是插入相同位置的记录,彼此不会互相等待。

    例如有索引记录4和7,当不同的事务试图分别插入5和6,在获得插入行的X锁之前,会首先获得4和7之间的间隙上的插入意向锁。

    但他们不会互相阻塞,因为他们插入的不是相同的行。


  • AUTO-INC LOCK (table-level)

    Auto-inc锁是一种特殊的表级锁,事务插入具有自增列的表时需要获得此锁。

    简单的说,就是一个事务正在插入表,那么其他插入表的事务必须等待这个当前插入事务完成,以保证主键值的连续。

    配置参数innodb_autoinc_lock_mode控制auto-increment 锁所使用的算法。


  • predicate locks for spatial indexes

    空间索引。

    InnoDB为特殊列提供了SPATIAL index。

    处理使用SPATIAL indexes时,next-key不能很好的支持REPEATABLE READ或者SERIALIZABLE事务隔离级别。因为对于多维的数据,并没有明确的顺序,因此没有“next-key“的概念。

    为了支持SPATIAL indexes表的事务隔离级别,InnoDB使用predicate locks。

    SPATIAL index包含 minimum bounding rectangle(MBR)数据,因此在查询时,InnoDB通过在MBR数据上加predicate lock来实现一致性读。如果查询条件一致,其他的session不能插入或修改这条数据。

  • No labels