【mysql】MySQL中的锁原理(表锁、行锁、间隙锁、共享锁、排他锁)
发布日期:2021-05-08 11:05:00 浏览次数:33 分类:精选文章

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

MySQL锁机制深入解析

MySQL中的锁机制是数据库管理中的核心内容之一,用于保证多个进程或纯线程对资源的并发访问互斥性。本文将从不同存储引擎的锁机制、表锁与行锁的兼容性、InnoDB的行锁实现方式以及事务管理等方面进行详细分析。

1. MySQL表锁与行锁概述

MySQL的锁机制在不同的存储引擎中有所不同,这种差异主要体现在锁的实现方式和性能特性上。以下是MySQL中常见的锁类型:

  • 表锁:默认情况下,MyISAM和MEMORY存储引擎使用表锁。表锁的特点是锁定粒度大,锁冲突概率高,但加锁速度快,死锁概率低。表锁分为两种模式:共享读锁(Table Read Lock)和独占写锁(Table Write Lock)。

  • 行锁:InnoDB存储引擎默认使用行锁,锁定粒度更细,锁冲突概率更低,但加锁速度和资源消耗也更高。行锁同样分为共享锁(S锁)和排他锁(X锁)。

  • 页面锁:BDB存储引擎使用页面锁,锁定粒度介于表锁和行锁之间,但页面锁难以精细控制,锁冲突概率较高。

MySQL的锁机制可以归纳为以下三种类型:

  • 表锁:开销小,加锁快,不会出现死锁,锁定粒度大,发生锁冲突概率最高,并发度最低。
  • 行锁:开销大,加锁慢,容易发生死锁,锁定粒度最小,发生锁冲突概率最低,并发度最高。
  • 页面锁:开销和加锁时间介于表锁和行锁之间,锁定粒度介于表锁和行锁之间,并发度一般。
  • 2. MySQL表锁的详细分析

    2.1 表锁的锁模式

    MySQL的表锁分为两种模式:共享读锁(Table Read Lock)和独占写锁(Table Write Lock)。

    • 共享读锁:允许其他用户对同一表进行读操作,但会阻塞对同一表的写操作。
    • 独占写锁:只允许持有锁的线程对表进行写操作,阻塞其他用户的读和写操作。
    2.2 锁模式兼容性

    MySQL的表锁兼容性如下:

    • 共享读锁与共享读锁:兼容。
    • 共享读锁与独占写锁:不兼容,会阻塞。
    • 独占写锁与独占写锁:不兼容,会阻塞。
    2.3 加表锁的语法
    LOCK TABLES tbl_name { READ | WRITE }, [tbl_name { READ | WRITE }, ...]
    UNLOCK TABLES
    2.4 MyISAM表锁的特殊性

    MyISAM存储引擎默认使用表锁,但在执行查询时会自动加锁。以下是手动加锁的示例:

    LOCK TABLES orders READ LOCAL, order_detail READ LOCAL;
    SELECT SUM(total) FROM orders;
    SELECT SUM(subtotal) FROM order_detail;
    UNLOCK TABLES;

    注意事项:

  • LOCAL选项允许在表尾并发插入记录。
  • 必须同时加锁所有涉及表的锁,否则会导致错误。
  • 2.5 MyISAM并发锁

    MyISAM支持并发插入,可以通过设置concurrent_insert系统变量和使用LOCAL锁定来优化。concurrent_insert可设置为0、1或2,影响并发插入的能力。

    2.6 锁调度优化

    MyISAM的锁调度机制默认为写优先,可以通过设置LOW_PRIORITY_UPDATES参数或在查询中指定LOW_PRIORITY属性来调整优先级。

    3. InnoDB锁机制详解

    3.1 行锁与事务ACID属性

    InnoDB的事务支持ACID属性,包括原子性、一致性、隔离性和持久性。事务的核心目标是保证数据的一致性和完整性。

    3.2 并发事务问题及解决方案

    并发事务带来以下问题:

  • 更新丢失:多个事务修改同一数据,最后一个事务的修改覆盖前面的。
  • 脏读:事务读取其他事务未提交的数据。
  • 不可重复读:事务读取数据时,数据已被修改。
  • 幻读:事务读取数据时,数据版本变化。
  • 3.3 事务隔离级别

    ISO/ANSI SQL92定义了四个隔离级别:

  • 读未提交(Read Uncommitted):最低隔离级别,可能出现脏读。
  • 读已提交(Read Committed):只允许已提交的事务读取数据,避免脏读。
  • 可重复读(Repeatable Read):允许多次读取同一数据版本,避免不可重复读。
  • 串行化(Serializable):最高隔离级别,确保事务的原子性。
  • 3.4 InnoDB行锁争用分析

    可以通过以下命令查看InnoDB行锁状态:

    SHOW STATUS LIKE 'innodb_row_lock%';

    innodb_row_lock_waitsinnodb_row_lock_time_avg值表明锁冲突严重。

    3.5 InnoDB行锁模式

    InnoDB行锁包括共享锁(S锁)和排他锁(X锁),并使用意向锁(IS锁和IX锁)来实现多粒度锁机制。

    3.6 行锁实现原理

    InnoDB行锁通过索引记录锁定数据行,仅在索引条件检索时使用行锁,否则使用表锁。

    3.7 间隙锁与Next-Key Locks
  • 间隙锁(Gap Lock):用于防止幻读,锁定数据行的间隙范围。
  • Next-Key Locks:锁定索引记录及其后续间隙。
  • 3.8 使用表锁的特殊情况

    InnoDB在以下情况下可以使用表锁:

  • 更新大部分或全部数据时。
  • 涉及多个表的事务,避免死锁。
  • 注意事项:

  • 使用LOCK TABLES时,必须设置AUTOCOMMIT=0,并在事务结束前使用UNLOCK TABLES
  • InnoDB默认不支持表锁,需手动加锁。
  • 3.9 死锁处理

    InnoDB容易发生死锁,常见原因包括:

  • 意向锁冲突。
  • 不同隔离级别的事务竞争锁。
  • 锁等待时间过长。
  • 4. 总结

  • MyISAM表锁

    • 表锁默认开销小,加锁快,锁定粒度大。
    • 支持并发插入,适合读多写少的场景。
    • 锁调度以写优先,适合写操作为主的应用。
  • InnoDB行锁

    • 行锁默认实现,锁定粒度细,资源利用率高。
    • 支持多粒度锁机制,锁冲突概率低。
    • 事务支持ACID属性,提供强一致性。
  • 事务管理

    • 合理选择隔离级别,减少锁冲突。
    • 避免长时间锁持有,优化SQL语句。
    • 使用表锁解决特定场景下的锁冲突。
  • 通过合理设计索引、优化业务逻辑和调整锁策略,可以有效减少锁冲突和死锁,提升数据库性能。

    上一篇:【mysql】事务隔离与mvcc的误区
    下一篇:【mysql】全表扫描过程 & 聚簇索引 区别和联系

    发表评论

    最新留言

    第一次来,支持一个
    [***.219.124.196]2025年04月16日 06时43分20秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章

    EnvironmentNotWritableError: The current user does not have write permissions to the target environm 2025-03-28
    kali安装docker(亲测有效) 2025-03-28
    Linux系列:Linux目录分析:[/] + [/usr] + [/usr/local] + [/usr/local/app-name]、Linux最全环境配置 + 动态库/静态库配置 2025-03-28
    mysql系列:远程连接MySQL错误“plugin caching_sha2_password could not be loaded”的解决办法 2025-03-28
    Nmap端口服务 之 CentOS7 关于启动Apache(httpd)服务、telnet服务、smtp服务、ftp服务、sftp服务、snmp服务 2025-03-28
    PHP系列:PHP 基础编程 2(时间函数、数组---实现登录&注册&修改) 2025-03-28
    PHP系列:使用PHP实现登录注册功能的完整指南 2025-03-28
    Python&aconda系列:cmd/powershell/anaconda prompt提示“系统找不到指定的路径”(亲测有效) 2025-03-28
    Python&aconda系列:(W&L)Conda使用faiss-gpu报错及解决办法、安装numpy的坑、cmd执行Python脚本找不到第三方库、安装tensorflow-gpu时遇到的from 2025-03-28
    python&anconda 系列:Pycharm在debug问题的N种解决方案(一般程序、web方向、人工智能方向) 2025-03-28
    python&anconda系列(亲测有效):tensorflow AttributeError: ‘str’ object has no attribute ‘decode’ 2025-03-28
    python&anconda系列:tf.keras.backend.get_session()和keras.backend.get_会话()返回不同的会话对象(待解答) 2025-03-28
    "WARNING: Increasing RAM size to 1GB" and "Cannot set up guest memory 'xxx.ram': Invalid argument". 2025-03-28
    #if 0 #elif 1 #else #endif 用法 2025-03-28
    (反射+内省机制的运用)简单模拟spring IoC容器的操作 2025-03-28
    (转)tomcat7.0 manager app和host manager web管理 2025-03-28
    (转)在CListView列表视图中添加右键菜单的方法 2025-03-28
    .Net(C#)实现异步编程 2025-03-28
    .Net中webBrowser控件JS交互 2025-03-28
    .Net中webBrowser控件指定IE版本 2025-03-28