博客
关于我
Mysql Innodb 锁机制
阅读量:795 次
发布时间:2023-02-10

本文共 2318 字,大约阅读时间需要 7 分钟。

InnoDB 锁机制详解

InnoDB 是 MySQL 的一个高度可靠的存储引擎,特别适用于处理高并发和复杂的事务性数据应用。其锁机制是保证数据库一致性和高性能的关键组成部分。本文将深入探讨 InnoDB 的锁机制,包括 latch 与 lock 的实现、共享锁与排他锁的作用、行锁算法以及死锁案例分析。

Latch 与 Lock

InnoDB 的锁机制可以分为两大类:latch(闩锁)和 lock(数据库锁)。

Latch

Latch 被称为“轻量级锁”,其特点是获取和释放速度极快,适用于对短时间内对临界资源的控制。在 InnoDB 中,latch 又可以分为两种类型:

  • mutex(互斥锁):用于防止并发线程同时访问相同资源。
  • rwlock(读写锁):允许多个读操作同时进行,但排他锁操作必须等待。

需要注意的是,InnoDB 没有死锁检测机制,开发者需要通过合理的锁定策略来避免死锁。

Lock

数据库提供的锁机制,用于锁定数据资源。与 latch 不同,lock 的持有时间通常较长,且数据库引擎会在事务提交或滚back 时释放资源。lock 具有死锁检测机制,能够在必要时自动解决死锁问题。

共享锁与排他锁

InnoDB 提供两种标准的行级锁:

  • 共享锁 (S):允许事务读取一行数据。
  • 排他锁 (X):允许事务对数据进行更新或删除操作。

此外,InnoDB 还支持意向锁:

  • 意向共享锁 (IS):事务希望对某些数据行加共享锁。
  • 意向排他锁 (IX):事务希望对某些数据行加排他锁。

行锁算法

InnoDB 提供三种行锁算法:

  • 记录锁 (Record Lock):锁定单个记录。
  • 间隙锁 (Gap Lock):锁定一个范围,但不包含记录本身。
  • 下一个键锁 (Next-key Lock):结合间隙锁和记录锁,锁定一个范围,并锁定记录本身。
  • 这些算法共同确保了在并发访问下数据的一致性和完整性。

    MySQL 加锁机制

    在默认的 RR 隔离级别下,InnoDB 的行锁是对索引加锁,扫描过程中对边界行加锁。如果使用的是二级索引,除了对二级索引加锁,还需对主键聚簇索引加锁。

    需要注意的是,InnoDB 在加锁时会锁定更多行数,尤其是在支持 Index Condition PushDown 的情况下(如 MySQL 5.6),这可能导致锁定数量远超实际需要的行数。

    加锁原因

    例如,语句 A 使用二级索引更新数据,语句 B 使用聚簇索引更新数据。如果 A 只对二级索引加锁,B 可能无法感知 A 的存在,违反了同一数据行更新必须串行执行的约束。因此,必须同时锁定主键和二级索引。

    select * from table where?

    在不同的隔离级别下,select 操作对锁定机制有不同的影响:

    • RC 隔离级别:无需加锁,使用快照读,可能导致前后读取数据不一致。
    • RR 隔离级别:无需加锁,使用快照读,确保读取的是事务开始时的数据版本。
    • Serializable 隔离级别:需要加锁,InnoDB 会将 select 转换为 select ... lock in share mode。

    insert?

    插入操作会对插入成功的行加记录锁,不会阻止其他事务插入前一版本的数据。插入之前,会在间隙加意向锁。如果遇到 duplicate-key error,会对冲突记录加共享锁。这种情况下可能导致死锁,例如两个 insert 对同一记录的共享锁相互等待。

    delete?

    delete 操作仅设置 delete_flag 为 1,实际删除延迟到 purger 过程。delete 时:

    • 找到满足条件的记录且有效,加排他锁。
    • 找到满足条件的记录但无效,加 next-key 锁。
    • 未找到满足条件的记录,加 gap 锁。

    update?

    更新操作对满足条件的记录加 next-key 锁。如果是等值匹配且使用唯一索引或聚簇索引,可以只加记录锁。需要注意 NULL 值的处理:在唯一索引中含 NULL 的记录不会加记录锁,而是加 next-key 锁。

    死锁案例分析

    3 个 insert 的死锁

    以下是一个典型的死锁案例:

    • 事务 A 插入记录 (4,996,3,4,5)。
    • 事务 B 和事务 C 也插入相同数据,由于索引冲突,转为加共享锁。
    • 事务 A 滚back,释放排他锁,B 和 C 需要获取排他锁,但因互相持有共享锁,导致等待,引发死锁。

    2 个 update 的死锁

    以下是一个死锁案例:

    • 事务 A 更新 deadlocktest force index(I_b) set e = sleep(5) where b > 0。
    • 事务 B 更新 deadlocktest force index(I_c) set e = sleep(5) where c > 2。
    • 两者加锁顺序不同,导致无法及时释放锁,引发死锁。

    3 个以上 delete 的死锁

    以下是一个死锁案例:

    • 事务 A、B 和 C 同时删除 a=550 的记录。
    • 事务 A 加共享锁,B 和 C 加排他锁。
    • 事务 A 滚back,释放锁,B 和 C 因为索引冲突而竞争锁,导致死锁。

    死锁防治建议

    • 合理设计索引,避免过多索引导致锁冲突。
    • 选择适当的隔离级别,减少锁竞争。
    • 合理控制并发度,避免过多高并发操作。
    • 定期监控锁等待情况,及时发现死锁潜在点。

    参考文献

    本文的内容参考了多个官方文档和实践经验,具体包括:

    • MySQL 官方文档
    • InnoDB 开发者手册
    • 相关技术博客和案例分析

    通过合理的锁定策略和优化数据库设计,可以有效避免死锁问题,提升数据库性能和可靠性。

    转载地址:http://keffk.baihongyu.com/

    你可能感兴趣的文章
    mysqli
    查看>>
    MySQLIntegrityConstraintViolationException异常处理
    查看>>
    mysqlreport分析工具详解
    查看>>
    MySQLSyntaxErrorException: Unknown error 1146和SQLSyntaxErrorException: Unknown error 1146
    查看>>
    Mysql_Postgresql中_geometry数据操作_st_astext_GeomFromEWKT函数_在java中转换geometry的16进制数据---PostgreSQL工作笔记007
    查看>>
    mysql_real_connect 参数注意
    查看>>
    mysql_secure_installation初始化数据库报Access denied
    查看>>
    MySQL_西安11月销售昨日未上架的产品_20161212
    查看>>
    Mysql——深入浅出InnoDB底层原理
    查看>>
    MySQL“被动”性能优化汇总
    查看>>
    MySQL、HBase 和 Elasticsearch:特点与区别详解
    查看>>
    MySQL、Redis高频面试题汇总
    查看>>
    MYSQL、SQL Server、Oracle数据库排序空值null问题及其解决办法
    查看>>
    mysql一个字段为空时使用另一个字段排序
    查看>>
    MySQL一个表A中多个字段关联了表B的ID,如何关联查询?
    查看>>
    MYSQL一直显示正在启动
    查看>>
    MySQL一站到底!华为首发MySQL进阶宝典,基础+优化+源码+架构+实战五飞
    查看>>
    MySQL万字总结!超详细!
    查看>>
    Mysql下载以及安装(新手入门,超详细)
    查看>>
    MySQL不会性能调优?看看这份清华架构师编写的MySQL性能优化手册吧
    查看>>