当前位置: 首页 > news >正文

MySQL锁机制

1. MySQL锁机制

锁机制的概念:

数据库是多用户共享的系统,为了应对并发访问,MySQL 设计了多种锁机制,用于协调用户对资源的访问,避免数据不一致或冲突。

按作用范围分类的锁类型:

锁类型

加锁对象

粒度

特点

全局锁

整个数据库实例

最粗粒度

会阻塞所有线程的写操作

表级锁

某一张表

中等粒度

包括表锁、元数据锁

行级锁

表中的某一行

最细粒度

并发性好,开销大

1.1. 全局锁(Global Lock)

1. 命令用法

FLUSH TABLES WITH READ LOCK;
  • 简称 FTWRL
  • 当前会话持有全局读锁时,其它线程无法进行写操作或表结构变更

2. 加锁效果

  • 所有表变为只读状态
  • 阻塞操作
  • 所有 DML(如 INSERT、UPDATE、DELETE)
  • 所有 DDL(如 ALTER、DROP)
  • 事务提交(因为事务可能带有写入操作)

3. 使用场景:

全库逻辑备份

  • 为了避免备份时数据不一致,需要确保在备份过程中没有其他写操作。
  • 若不加锁:可能某些表的快照来自不同时间点,导致恢复后数据逻辑不一致。

举例:

mysqldump -A --lock-all-tables

此参数会自动执行 FTWRL 来确保一致性备份。

❌ 不加锁的风险

假设有两个表:

  • 用户表 users
  • 课程表 courses

先备份 users,然后用户购买了课程,再备份 courses,恢复时:

  • 用户存在,但课程购买记录不存在
  • 数据逻辑不一致

更优备份方案(推荐方式)

使用事务一致性备份,single-transaction 方法:

mysqldump -A --single-transaction --quick --master-data=2

前提条件:

  • 所有表均为 InnoDB(支持事务)
  • 使用的是 RR(可重复读)隔离级别

在备份开始时启动一个事务,依赖 MVCC(多版本并发控制) 拿到一致性快照,即使期间有更新,也不影响当前事务读到的数据。

SET GLOBAL readonly=1 与 FTWRL 对比

项目

readonly=1

FTWRL

加锁方式

设置系统变量

显式命令加锁

持久性

需手动恢复

会话断开自动释放

影响

所有客户端都无法写

当前会话可读,其它会话禁止写

场景

主备切换保护主库只读

逻辑备份等临时场景更合适

风险

客户端异常断开后仍为只读

自动释放风险小

1.2. 表级锁(Table-level Lock)

表级锁:

1. 表锁

  • 定义:表锁是对整个数据库表进行加锁,限制了其他事务对该表的访问。表锁的语法是 lock tables … read/write。需要显示使用
  • 作用:当一个事务需要对整个表进行操作时,可以申请表级锁,确保在操作过程中其他事务不能修改或访问该表。
  • 粒度:粗粒度锁,锁定整个表,因此可能会影响到其他事务对表中其他行的操作。
  • 并发性:低,并发度较差,因为其他事务需要等待锁释放才能访问整个表。

2. 元数据锁MDL(metadata lock)

  • 定义:元数据锁是用于保护数据库的元数据(例如表结构、索引信息等)的锁。MDL 不需要显式使用,在对一个表做增删改查操作的时候会被自动加上。MDL 的作用是,保证读写的正确性
  • 作用:当一个事务需要修改表结构等元数据信息时,会申请元数据锁,确保在修改过程中其他事务不能同时修改相同的元数据。
  • 粒度:较细粒度,锁定特定的元数据对象,例如一个表的结构。
  • 并发性:相对较好,因为不同事务可能修改不同的元数据对象,不会相互阻塞。

表锁:

表锁一般是在数据库引擎不支持行锁的时候才会被用到的。

使用方式:

LOCK TABLES table1 READ, table2 WRITE;
-- 操作表
UNLOCK TABLES;

锁类型:

  • READ:本线程只能读,其他线程只能读,不能写
  • WRITE:本线程能读写,其他线程不能读也不能写

注意:

  • 当前会话只能访问被锁定的表
  • 如果忘记 UNLOCK,其他线程将被阻塞

InnoDB 中不推荐使用:因为它本身支持行锁,粒度更细并发性更好

元数据锁:

作用:

保护表的结构元数据,防止以下问题:

  • 查询时结构变化 → 报错或数据错乱
  • 修改结构时有读写并发 → 破坏一致性

加锁行为(自动触发):

  • 读锁:任何访问表数据的操作(SELECT、UPDATE、INSERT 等)都会加上
  • 写锁:任何修改表结构的操作(ALTER、DROP 等)

锁冲突规则:

当前锁类型

新请求锁类型

是否冲突

读锁

读锁

读锁

写锁

写锁

任意

1.3. 行锁

行锁作用范围: 行级锁作用于数据表中的行记录,是 InnoDB 的重要特性之一。

引擎支持情况:

  • InnoDB:✅ 支持行锁,支持高并发。
  • MyISAM:❌ 不支持行锁,只支持表级锁,容易成为并发瓶颈。

优势: 行锁粒度小,锁冲突少,适合高并发场景。

两阶段协议

两阶段协议的概念:

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。

加锁时机: 事务在执行语句时需要资源才加锁(即时加锁)。

释放时机: 所有加的锁都等到事务提交或回滚时统一释放(延迟释放)。

设计建议:

  • 如果事务需要锁多行,尽量把可能造成锁冲突的语句放在后面执行,缩短热点行的持锁时间,提升并发性能。

在线购票系统中,更新影院账户余额的语句最可能造成冲突,建议将其放在事务末尾执行。

死锁与死锁检测

死锁定义:

  • 死锁是指多个事务因持有并等待对方资源而进入无限等待的状态。

举例:

事务 A 锁了记录 1,等待记录 2;

事务 B 锁了记录 2,等待记录 1;

二者形成循环依赖,系统进入死锁。

死锁处理策略:

  • 等待超时退出

含义:直接进入等待,直到超时。

参数:innodb_lock_wait_timeout(默认 50 秒)

缺点:响应时间不可控,容易引发业务超时失败。

  • 主动死锁检测(推荐)

含义:发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。

参数:innodb_deadlock_detect=on(默认开启)

优点:可快速发现死锁并中断其中一个事务。

成本:每次加锁时都要做图遍历判断是否存在环路,时间复杂度为 O(n),代价大。

热点行引发的性能问题与优化方案

问题现象:

多个事务同时更新同一热点行(如影院账户),即使没有真正死锁,也会因频繁做死锁检测而导致:CPU 利用率高,但实际 TPS(每秒事务数)很低。

解决方案:

1. 临时关闭死锁检测(不推荐)

  • 仅适用于能明确保证业务无死锁的情况。
  • 设置:innodb_deadlock_detect=off
  • 缺点:死锁不会被自动处理,会等待到超时,影响业务体验。

2. 控制并发度

  • 在数据库服务端或中间件中,对热点记录的访问请求排队处理,减少并发冲突。
  • 客户端控制并发不可靠,因客户端数量不可控。

3. 数据结构改造:热点行拆分为多行

  • 例:将影院账户拆分为 10 个记录,每次随机更新其中一条。
  • 优点:减少锁竞争,降低死锁检测的频率。
  • 注意事项:若涉及金额减少或查询总额,需额外逻辑处理。

相关文章:

  • 【PostgreSQL 03】PostGIS空间数据深度实战:从地图服务到智慧城市
  • QT入门学习
  • 4.2.4 Spark SQL 数据写入模式
  • CppCon 2014 学习:Pragmatic Type Erasure
  • vue3 el-input type=“textarea“ 字体样式 及高度设置
  • Axure中继器交互完全指南:核心函数解析×场景实战×避坑策略(懂得才能应用)
  • 2025山东CCPC题解
  • 鸿蒙编译ffmpeg库
  • leetcode17.电话号码的字母组合:字符串映射与回溯的巧妙联动
  • 什么是trace,分布式链路追踪(Distributed Tracing)
  • 自动驾驶系统研发系列—端到端自动驾驶:愿景、陷阱与现实博弈
  • [笔记]一般小信号测量方法
  • sass高阶应用
  • 触发器与存储过程详解
  • C语言之编译器集合
  • Spring Boot养老院管理系统源码分享
  • Angularjs-Hello
  • 【Java开发日记】基于 Spring Cloud 的微服务架构分析
  • Java开发中常见的数值处理陷阱与规避方法
  • Kafka消息中间件
  • 湖南益阳网站建设/百度客服电话24小时人工服务热线
  • 大连做网站开发的公司/厦门网站seo哪家好
  • 福建八大员建设厅延续的网站/钓鱼网站制作教程
  • 网站项目分析怎么做 方法有哪些/百度官网电话
  • 网站交互功能/市场营销策划方案3000字
  • 做网站横幅的软件/怎样制作一个自己的网站