作者: 简书徐小耳 | 来源:发表于2018-11-30 22:04 被阅读25次

锁的概述

  • http://hedengcheng.com/?p=771#_Toc374698317
  • next key=record+gap record 锁住主键或者唯一索引,而gap 则锁住非辅助索引的上下两条记录的范围
    http://blog.sina.com.cn/s/blog_a1e9c7910102vnrj.html
  • 行级锁只有当实现本身会增加开销其才增加开销
  • innodb存储引擎不需要锁升级,因为一个锁和多个锁开销是相同的(采用一个页一个位图,一个页管理其中记录的锁)
  • 锁是针对索引的(也可以看为某一列加锁,因此如果我们只对主键加索引,辅助索引没有锁,则辅助索引插入不耗时)
  • next lock key 总是做开右闭(感觉不是正确的,如果是小于的范围查询或者大于的范围查询 感觉 都不ok,可以理解为当我们为等于范围查询才是左开右闭)
  • 默认情况下,InnoDB工作在可重复读隔离级别下,并且会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。Next-Key Lock是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。
  • 间隙锁(Gap Lock)一般是针对非唯一索引而言的,test表中的v1(非唯一索引)字段值可以划分的区间为
  • 行锁锁定的是索引记录,而不是行数据,也就是说锁定的是key。

lock与latch

  • 两者都是锁,latch成为轻量级的锁,因为其要求所得的时间必须非常短。若持续时间长,则应用的性能会非常差。
  • 在innodb中 latch 包含mutex(互斥锁)和rwlock(读写锁)
  • latch 没有死锁的检测机制
  • latch主要是用来管理并发线程操作临界资源
  • lock的对象是事务,锁定的是数据库中的对象,如表,页,行。
  • lock 只有在事务commit或者rollback后进行释放(当然不同的事务隔离级别释放时间可能不一致)
  • lock 有死锁检测机制


    image.png
  • 通过 show engine innodb mutex 查看mutex锁


    image.png

innodb存储引擎中的锁

  • 行锁类型:共享锁(s)允许事务读一行数据,排他锁(X)允许事务更新或者删除一行数据
  • 如果一行数据的S锁被事务1获取,则事务2只能获取该行的S锁。不能获取X锁。
  • 意向锁(IX)支持多粒度锁定,即允许事务在表级锁(表级锁就是意向锁)和行级锁都存在的情况。
  • 意向锁意味着事务希望在更细的粒度加锁
  • 意向锁就是表级锁,意向锁的类型有意向共享锁(IS Lock),意向排他锁(IX Lock)
  • 意向锁只会阻塞除全表扫描的请求


    image.png
  • 为什么要意向锁
  • 1.锁是由一个独立的数据结构去维护的,比如我们有一个事务正在修改某一行,即获取了X锁。
    1. 此时事务B想做全表扫描,那么他需要一层层遍历锁的数据结构,看看是否存在X锁,这就很损耗性能
  • 3.我们获取某个行锁的时候会设置表的意向锁,这个时候,如果有全表扫描,则在表级别就知道是否可以进行该事务,而不需要进行迭代
  • 一致性非锁定读
  • 即可以通过读取行的不同版本来避免需要获取锁来读
  • 当我们读取一行正在执行delete或者update的数据 我们可以不等锁释放而读取其快照
  • 所谓的快照就是undo,undo是实现事务原子性
  • 当然这个特性只能时候特定的隔离级别
  • 一个记录有不止一个快照数据,这就是MVCC
  • read committed和repeatable read隔离级别 都会使用一致性非锁定读,但是他们读取的快照定义不同
  • read committed 读锁非锁定行的最新一份快照,或者改行最新数据(前提是改行没有X锁),该特性违背事务的隔离性。
  • repeatable read非一致性读总是读取事务开始时候的行数据版本,即这个读事务开始的行数据版本(即每个快照都有一个事务id,这个事务id是最靠近读事务id的,在这个读期间 就算新增无数个事务id 也不会管)
  • 不可重复读是指读到别人提交的事务
  • 一致性锁定读
  • select ... for update(X锁)
  • select ...Lock in share mode(S锁)
  • 上面x锁的 我们可以采用一致性非锁定读 某行的时候,可以读取已经被select ... for update锁定的行,原因是一样的 即 读取快照
  • 上面两个语句必须在事务中

自增长与锁

  • 每个自增长的值的表都一个自增长计数器,当我们对含有自增长的计时器的表进行插入操作时,这个计时器会被初始化
  • 这其实是一个自增长锁,为了提高插入性能,锁在一个sql语句执行完就释放,而不是整个事务结束。
  • 为了提高插入的性能 引入了轻量级互斥量的自增长机制。提了一个参数 innodb_autoinc_lock_mode来控制自增长的模式,该参数的默认值是1


    image.png
    image.png

外键和锁

  • 我们更新外键会采用select ...Lock in share mode(S锁),这样可以避免数据不一致,

锁的算法

6.4.1行锁的3种算法

  • record lock :单个行记录锁
  • gap lock :间隙锁,锁定一个范围,但并不包含记录本上
  • Next-Key lock=gap lock+record lock 锁定一个范围,并且锁定记录本身。
  • record lock如果没有设置任何索引,innodb会设置隐式的注解来锁定记录
  • Next-Key lock 是结合gap lock+record lock,现在默认的对于行的查询都是采用这种锁定算法
  • Next-Key lock 可以解决幻读
  • 幻读是当我们准备插入id=1的时候我们回去先查下 再去插入这个数据,如果这个时候在插入的时候突然被别人插入id=1,导致我们插入失败。这就是幻读,我们可以通过Next-Key lock 在查下的时候加锁
  • MVCC是解决读写并行的幻读,而next key lock 是解决写写并行的幻读
  • 不可重复读 一般是指读出来的记录条数没变 但是记录内容不一样
  • 幻读 一般是我们读取的记录被新增或删除
  • 两者都是读到了别人已提交的事务
  • 我们通过MVVC 可以解决不可重复读(即读取事务没有修改前的记录)
  • next-key- lock 则是不让其他事务修改被我们读取到的记录,这样就不会在我们读取的时候 我们想修改结果,结果发现这个结果已经被别人修改了
image.png

锁升级

  • 锁升级就是将锁的粒度降低,比如吧一个表的1000个行锁升级为一个页锁,把页表升级为表锁。
  • innodb存储引擎不存在锁升级的问题,因为其不是根据每个记录来产生行锁的。
  • 采用页对锁进行管理,采用的是位图。所以 锁住一个还是多个 开销差距不大。我们可以理解为一个页就是bitmap 然后里面的每一个记录就是该记录的锁
  • 一般锁升级可以节省开销,但是因为我们innodb
  • 在read committed隔离级别下,存在不可重复读和幻读现象。

相关文章

网友评论

      本文标题:

      本文链接:https://www.haomeiwen.com/subject/wpnxcqtx.html