其他分享
首页 > 其他分享> > Innodb锁相关总结

Innodb锁相关总结

作者:互联网

一、InnoDB共有七种类型的锁:
(1)共享/排它锁(Shared and Exclusive Locks)
(2)意向锁(Intention Locks)
(3)插入意向锁(Insert Intention Locks)
---InnoDB并发插入,居然使用意向锁? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961461&idx=1&sn=b73293c71d8718256e162be6240797ef&chksm=bd2d0da98a5a84bfe23f0327694dbda2f96677aa91fcfc1c8a5b96c8a6701bccf2995725899a&scene=21#wechat_redirect
插入意向锁,是间隙锁(Gap Locks)的一种(所以,也是实施在索引上的),它是专门针对insert操作的。
多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
例如:在MySQL,InnoDB,RR下:
t(id unique PK, name);
数据表中有数据:
10, shenjian
20, zhangsan
30, lisi
事务A先执行,在10与20两条记录中插入了一行,还未提交:
insert into t values(11, xxx);
事务B后执行,也在10与20两条记录中插入了一行:
insert into t values(12, ooo);
(1)会使用什么锁?
(2)事务B会不会被阻塞呢?
回答:虽然事务隔离级别是RR,虽然是同一个索引,虽然是同一个区间,但插入的记录并不冲突,故这里:
使用的是插入意向锁
并不会阻塞事务B
(4)记录锁(Record Locks)
记录锁,它封锁索引记录,例如:
select * from t where id=1 for update;
它会在id=1的索引记录上加X锁,以阻止其他事务插入,更新,删除id=1的这一行。
需要说明的是:
select * from t where id=1;
则是快照读(SnapShot Read),它并不加锁
(5)间隙锁(Gap Locks)
间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。
依然是上面的例子,InnoDB,RR:
t(id PK, name KEY, sex, flag);
表中有四条记录:
1, shenjian, m, A
3, zhangsan, m, A
5, lisi, m, A
9, wangwu, f, B
这个SQL语句
select * from t where id between 8 and 15 for update;
会封锁区间,以阻止其他事务id=10的记录插入。
画外音:
为什么要阻止id=10的记录插入?
如果能够插入成功,头一个事务执行相同的SQL语句,会发现结果集多出了一条记录,即幻影数据。
间隙锁的主要目的,就是为了防止其他事务在间隔中插入数据,以导致幻读。
如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。
(6)临键锁(Next-key Locks)
临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
更具体的,临键锁会封锁索引记录本身,以及索引记录之前的区间。
如果一个会话占有了索引记录R的共享/排他锁,其他会话不能立刻在R之前的区间插入新的索引记录。
依然是上面的例子,InnoDB,RR:
t(id PK, name KEY, sex, flag);
表中有四条记录:
1, shenjian, m, A
3, zhangsan, m, A
5, lisi, m, A
9, wangwu, f, B
PK上潜在的临键锁为:
(-infinity, 1]
(1, 3]
(3, 5]
(5, 9]
(9, +infinity]
临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。
InnoDB,select为啥会阻塞insert? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961471&idx=1&sn=da257b4f77ac464d5119b915b409ba9c&chksm=bd2d0da38a5a84b5fc1417667fe123f2fbd2d7610b89ace8e97e3b9f28b794ad147c1290ceea&scene=21#wechat_redirect
(7)自增锁(Auto-inc Locks) 插入InnoDB自增列,居然是表锁? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961455&idx=1&sn=4c26a836cff889ff749a1756df010e0e&chksm=bd2d0db38a5a84a53db91e97c7be6295185abffa5d7d1e88fd6b8e1abb3716ee9748b88858e2&scene=21#wechat_redirect
自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。
最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
例如:t(id AUTO_INCREMENT, name);,其中id为自增

二、共享/排它锁(Shared and Exclusive Locks)

  参考博客:https://blog.csdn.net/u014292162/article/details/83271299
  共享锁(Share Locks,记为S锁),读取数据时加S锁,也叫读锁。
  排他锁(eXclusive Locks,记为X锁),修改数据时加X锁,也叫写锁。
    (1)事务拿到某一行记录的共享S锁,才可以读取这一行;
    (2)事务拿到某一行记录的排它X锁,才可以修改或者删除这一行;
  其兼容互斥表如下:
   S X
    S 兼容 互斥
    X 互斥 互斥
   即:
    (1)共享锁之间不互斥,多个事务可以拿到一把S锁,读读可以并行;
    (2)排他锁与其他任何锁互斥,只有一个事务可以拿到X锁,写写/读写必须互斥;
  因此,一旦写数据的事务没有完成,数据是不能被其他事务读取的,这对并发度有较大的影响。写事务没有提交,读相关数据的select也会被阻塞。  
由于数据加排他锁后,读相关数据也会被阻塞,因此并发性很低,由此引出了MVCC多版本并发控制:
  参考博客:https://www.cnblogs.com/dongqingswt/p/3460440.html
  数据多版本是一种能够进一步提高并发的方法,它的核心原理是:
    (1)写任务发生时,将数据克隆一份,以版本号区分;
    (2)写任务操作新克隆的数据,直至提交;
    (3)并发读任务可以继续读取旧版本的数据,不至于阻塞;
  MVCC就是通过“读取旧版本数据”来降低并发事务的锁冲突,提高任务的并发度。

三、意向锁(Intention Locks)

  意向锁是指,未来的某个时刻,事务可能要加共享/排它锁了,先提前声明一个意向。
  意向锁有这样一些特点:
    (1)首先,意向锁,是一个表级别的锁(table-level locking);
    (2)意向锁分为:
      意向共享锁(intention shared lock, IS),它预示着,事务有意向对表中的某些行加共享S锁
      意向排它锁(intention exclusive lock, IX),它预示着,事务有意向对表中的某些行加排它X锁
      举个例子:
        select ... lock in share mode,要设置IS锁;
        select ... for update,要设置IX锁;
    (3)意向锁协议(intention locking protocol)并不复杂:
      事务要获得某些行的S锁,必须先获得表的IS锁
      事务要获得某些行的X锁,必须先获得表的IX锁
    (4)由于意向锁仅仅表明意向,它其实是比较弱的锁,意向锁之间并不相互互斥,而是可以并行,其兼容互斥表如下:
    IS IX
     IS 兼容 兼容
     IX 兼容 兼容
    (5)额,既然意向锁之间都相互兼容,那其意义在哪里呢?它会与表级的共享锁/排它锁互斥,其兼容互斥表如下:
           S X
      IS 兼容 互斥
      IX 互斥 互斥
  意向锁的作用就是:
    当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。
    如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。
    注:意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。



四、插入意向锁(Insert Intention Locks)

  ---InnoDB并发插入,居然使用意向锁? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961461&idx=1&sn=b73293c71d8718256e162be6240797ef&chksm=bd2d0da98a5a84bfe23f0327694dbda2f96677aa91fcfc1c8a5b96c8a6701bccf2995725899a&scene=21#wechat_redirect
  插入意向锁,是间隙锁(Gap Locks)的一种(所以,也是实施在索引上的),它是专门针对insert操作的。
  多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
  例如:在MySQL,InnoDB,RR下:
    t(id unique PK, name);
    数据表中有数据:
      10, shenjian
      20, zhangsan
      30, lisi
    事务A先执行,在10与20两条记录中插入了一行,还未提交:
      insert into t values(11, xxx);
    事务B后执行,也在10与20两条记录中插入了一行:
      insert into t values(12, ooo);
    (1)会使用什么锁?
    (2)事务B会不会被阻塞呢?
    回答:虽然事务隔离级别是RR,虽然是同一个索引,虽然是同一个区间,但插入的记录并不冲突,故这里:
使用的是插入意向锁
并不会阻塞事务B

标签:总结,事务,记录,互斥,Locks,插入,Innodb,意向锁,相关
来源: https://www.cnblogs.com/aiqiqi/p/10512051.html