• MySQL InnoDB 锁


    1 介绍

    行级锁不一定会增加开销。InnoDB存储引擎不需要锁升级,因为一个锁和多个锁的开销是相同的。
    位图存储,所以相同

    InnoDB提供一致性非锁定读、行级锁支持。

    lock与latch

    • latch一般被称为闩锁,是轻量级锁,要求锁定时间非常短,分为mutex互斥量、rwlock读写锁,保证并发线程操作临界资源的正确性,通常无死锁检测机制。我理解是对数据库本身各种线程请求资源加的锁
    • lock的对象是事务,锁定数据库中的对象,如表、页、行,有死锁机制。
    locklatch
    对象事务线程
    保护数据库内容内存数据结构
    持续时间整个事务过程临界资源
    模式行锁、表锁、意向锁读写锁、互斥量
    死锁通过waits-for graph、time out等机制进行死锁检测和处理无死锁检测和处理机制。仅通过应用程序加锁的顺序保证无死锁情况发生
    模式Lock Manager的哈希表中每个数据结构的对象中

    2. InnoDB存储引擎中的锁

    2.1 锁的类型

    InnoDB存储引擎实现了两种标准行级锁(S/X)

    • 共享锁(S Lock),允许事务读一行数据
    • 排它锁(X Lock),允许事务删除或更新一行数据

    两种锁的兼容性

    XS
    X不兼容不兼容
    S不兼容兼容

    不兼容是指a事务已经获取某行的X锁,b事务获取该行的X锁时会被阻塞

    InnoDB支持意向锁(Intention Lock)
    意向锁将锁定对象分为多个层次,意味着事务希望在更细粒度的对象上加锁。比如对象层次分为库->表->页->行,想对行上加锁,会先对库表页上加意向锁。

    XSISIX
    X不兼容不兼容不兼容不兼容
    S不兼容兼容兼容不兼容
    IS不兼容兼容兼容兼容
    IX不兼容不兼容兼容兼容

    意向锁之间是相互兼容的,因为他们的下一层(实际锁对象)之间没有冲突。

    2.2 一致性非锁定读

    一致性非锁定读是指InnoDB通过行多版本控制读取数据发现读取的行正在执行DELETE或UPDATE操作,则不会等待锁释放,而是读取快照数据。

    特点:

    • 不需要等待锁定行的锁释放,也不会对历史数据上锁,提高并发度
    • 通过undo段(用户事务回滚)完成,因此快照数据无额外开销

    在事务隔离级别READ COMMITTED和REPEATABLE READ下,InnoDB使用一致性非锁定读。

    • READ COMMITTED读取最新的快照数据
    • REPEATABLE READ读取事务开始时的行数据版本

    2.3 一致性锁定读

    由上节可知,某些隔离级别下的普通select语句都是一致性非锁定读,但是某些情况下需要对select操作进行一致性锁定读,InnoDB支持两种锁定读操作:

    • select … for update (悲观锁,X写锁)
    • select … lock in share mode (乐观锁,S读锁)

    2.4 MVCC多版本并发控制

    MVCC(Multi Version Concurrency Control),是一致性非锁定读用于不加锁读取数据,提高并发性的手段
    MVCC使用的读是快照度,也就是普通的select语句。快照读不加锁,可能读到历史数据。
    对于undo log、readview的讲解可以看这篇:https://www.cnblogs.com/qdhxhz/p/15750866.html

    3 锁的算法

    3.1 行锁的三种算法

    • Record Lock: 单行记录锁,锁某一行
    • Gap Lock:间隙锁,锁一个范围,不包含记录本身
    • Next-Key Lock:Record Lock+Gap Lock,锁定范围加本身

    Next-Key Lock算法下,索引有10,11,13三个值,则索引被锁的区间可能为:(-∞,10],(10,11],(11,13],(13,+∞)

    当查询的索引是唯一索引时,InnoDB会对Next-Key Lock进行优化,降级为Record Lock。
    InnoDB还会对辅助索引的下一个键值加上gap lock(如对11加锁会将(10,13)整体加上锁)。

    Gap Lock是为了阻止多个事务将记录插到同一范围内,能解决不可重复读的问题

    4 锁的问题

    • 脏读:一个事务读到了另一个事务未提交的数据
    • 不可重复读:一个事务内多次相同的查询语句查到的结果不同,因为其他事务提交的数据影响了当前事务
    • 丢失更新:一个事务的更新操作被另一个事务的更新覆盖。数据库层面下不会发生这种问题,因为任何隔离级别都对数据操作都会加锁

    5 死锁

    概念:两个或两个以上的事务在执行过程中,因争抢锁资源造成互相等待导致无法前进。

    死锁的两种解决方式:超时、死锁检测

    5.1 超时

    设置某事务等待超过某时间后,进行回滚,释放资源。通过innodb_lock_wait_timeout设置超时时间

    • FIFO顺序回滚
    • 更新行数较多,占用undo log较大,回滚花费时间可能较长

    5.2 死锁检测

    wait-for graph 等待图,一种主动的死锁检测机制,通过锁信息链表和事务等待链表构造图。

    5.3 两种方式优缺点

    • 超时:
      • 缺点:超时时间难以把控,时间过长系统难以接受,时间过短容易误伤正常的事务。回滚事务undo log日志可能较多。
      • 优点:底层逻辑简单,保底手段
    • 死锁检测:
      • 缺点:一旦阻塞就会检测,大量事务更新同key可能会浪费大量CPU资源进行死锁检测
      • 优点:存在死锁时回滚undo log少的事务

    热点更新的问题:
    热点更新会造成死锁检测花费大量CPU时间进行死锁检测,降低事务并发度。
    解决方式:

    • 关闭死锁检测,依靠超时解决:可能大量超时,影响系统性能
    • 控制并发度,在应用层或中间件控制同key串行更新

    6 锁升级

    InnoDB不存在锁升级的问题,其不是根据记录产生行锁,而是对每个页进行锁管理,采用位图的方式。因此锁页还是锁行开销是相同的。

    参考

  • 相关阅读:
    软件测试的风险主要体现在哪里
    php-java-net-python-报修修改计算机毕业设计程序
    Docker Compose
    顺序栈的实现----数据结构
    让预训练语言模型读懂数字:超对称技术联合复旦知识工场等发布10亿参数BigBang Transformer[乾元]金融大规模预训练语言模型
    sqlyog导入csv失败的解决方法
    Clickhouse 消除由group by产生的间隙
    【算法日志】图论 并查集及其简单应用
    3.msfconle
    Oracle-函数
  • 原文地址:https://blog.csdn.net/dreambyday/article/details/126352612