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

事务与mysql数据库锁的关系

        事务是紧密协同的核心机制:事务通过 ACID 特性(尤其是隔离性)定义数据操作的 “一致性边界”,而锁则是实现事务隔离性、解决并发冲突的 “底层工具”—— 没有锁的控制,事务的隔离性和数据一致性将无法保障。

        要理解二者的关系,需先明确核心前提:MySQL 的事务隔离性(如读已提交、可重复读)并非 “自动实现”,而是通过锁机制+MVCC(多版本并发控制) 共同完成(不同隔离级别对锁的依赖程度不同)。下面从 “锁的作用”“锁与事务隔离级别的绑定”“锁对事务生命周期的影响” 三个维度展开。

一、核心纽带:锁为事务解决 “并发冲突”

        事务并发执行时,最常见的冲突是 “读写冲突” 和 “写写冲突”:

  • 读写冲突:事务 A 读取数据时,事务 B 修改该数据(或反之),可能导致脏读、不可重复读;
  • 写写冲突:两个事务同时修改同一数据,可能导致数据覆盖(破坏原子性和一致性)。

        锁的核心作用就是通过 “互斥” 或 “共享” 规则,限制并发事务对同一数据的操作权限,从而避免上述冲突,保障事务隔离性。

二、MySQL 锁的分类:不同锁服务于不同事务场景

        MySQL 的锁按 “粒度” 和 “性质” 可分为多类,不同锁的设计目标直接对应事务的不同并发需求:

1. 按 “锁粒度” 划分(控制数据范围的大小)
锁类型锁定范围核心作用适用事务场景
行锁(Row Lock)单条数据行(如id=1的行)最小粒度的锁,仅锁定被操作的行,并发效率最高(其他事务可操作未锁定的行)高并发写场景(如电商订单修改、用户余额更新),避免 “锁范围过大导致并发堵塞”。
表锁(Table Lock)整个数据表最大粒度的锁,锁定整张表,并发效率最低(锁定期间其他事务无法写表)低并发、大批量操作场景(如全表删除delete from table、表结构修改alter table),避免行锁开销。
间隙锁(Gap Lock)数据行之间的 “间隙”(如id between 1 and 5的区间)锁定 “不存在的数据区间”,防止幻读(避免其他事务在间隙中插入新行)MySQL InnoDB 引擎的 “可重复读” 隔离级别中,用于解决 “当前读”(如select ... for update)的幻读问题。
临键锁(Next-Key Lock)行锁 + 间隙锁(如锁定id=3的行 +id=3前后的间隙)兼顾 “行级锁定” 和 “间隙锁定”,是 InnoDB 默认的行锁算法覆盖大部分行级操作场景,平衡 “并发效率” 和 “幻读防护”。
2. 按 “锁性质” 划分(控制操作权限)
锁性质核心规则对应事务操作并发兼容性(同一数据)
共享锁(S 锁,Shared Lock)事务获取 S 锁后,仅允许 “读数据”,不允许 “修改”select ... lock in share mode(手动加 S 锁)多个事务可同时加 S 锁(共享读);但禁止加 X 锁(防止写冲突)。
排他锁(X 锁,Exclusive Lock)事务获取 X 锁后,既允许 “读数据”,也允许 “修改数据”,且禁止其他事务干扰update/delete/insert(自动加 X 锁)、select ... for update(手动加 X 锁)仅允许一个事务加 X 锁;加 X 锁后,其他事务无法加 S 锁或 X 锁(完全互斥)。

三、锁与事务隔离级别的深度绑定

        MySQL 的 4 种事务隔离级别,本质是通过 “锁的使用策略”+“MVCC 的版本控制” 来实现的 —— 隔离级别越高,对锁的依赖越强(或锁定范围越大),并发效率越低。

        下面以 InnoDB 引擎(MySQL 默认引擎,支持事务和行锁)为例,说明不同隔离级别下锁的作用:

事务隔离级别锁策略与 MVCC 配合方式解决的并发问题(脏读 / 不可重复读 / 幻读)锁的开销与并发效率
读未提交(RU)几乎不使用锁,直接读取 “最新数据”(包括其他事务未提交的修改)均不解决(允许脏读、不可重复读、幻读)锁开销最低,并发最高(但数据一致性最差)
读已提交(RC)1. 普通查询(如select)用 MVCC 读 “已提交的版本”,不加锁;
2. 写操作(update等)自动加 X 锁(行级),阻塞其他 X 锁。
解决脏读;不解决不可重复读、幻读锁开销低,并发较高(Oracle 默认级别)
可重复读(RR)1. 普通查询用 MVCC 读 “事务启动时的版本”,不加锁(保证同一事务内读一致);
2. 写操作自动加 X 锁(行级)+ 间隙锁 / 临键锁(防止幻读)。
解决脏读、不可重复读;基本解决幻读(除特殊 “当前读”)锁开销中等,并发中等(MySQL 默认级别)
串行化(Serializable)1. 所有查询(包括普通select)自动加 S 锁;
2. 写操作加 X 锁;
3. 完全串行执行事务(一个事务结束后再执行下一个)。
解决所有并发问题(脏读、不可重复读、幻读)锁开销最高,并发最低(一致性最强)

四、事务生命周期对锁的影响:锁的 “持有与释放”

        锁的生命周期与事务的生命周期强绑定,这是避免 “锁泄漏” 和 “长期堵塞” 的关键规则:

  1. 锁的持有时机:事务执行 “写操作”(update/delete/insert)或 “手动加锁读”(select ... for update)时,InnoDB 会自动 / 手动为数据加锁(行锁 / X 锁等)。
  2. 锁的释放时机事务提交(commit)或回滚(rollback)后,该事务持有的所有锁会立即释放—— 这意味着:
    • 若事务执行时间过长(如包含复杂查询、外部接口调用),会导致锁长期持有,阻塞其他事务;
    • 若事务中先执行加锁操作(如update),后执行耗时操作(如日志写入),会显著增加锁等待时间。

        反例(错误的事务设计):

START TRANSACTION;
-- 1. 加X锁修改数据(此时锁已持有)
UPDATE user SET balance = balance - 100 WHERE id = 1;
-- 2. 执行耗时操作(如调用外部支付接口,耗时5秒)
CALL external_payment_api(); 
-- 3. 5秒后才提交,锁持有了5秒,期间其他修改id=1的事务会被堵塞
COMMIT;

        正例(优化的事务设计):

-- 1. 先执行耗时操作(无锁)
CALL external_payment_api(); 
START TRANSACTION;
-- 2. 快速加锁修改并提交(锁持有时间仅几十毫秒)
UPDATE user SET balance = balance - 100 WHERE id = 1;
COMMIT;

五、关键关系总结

  1. 锁是事务隔离性的 “实现工具”:事务需要隔离性来避免并发冲突,而锁通过 “互斥 / 共享” 规则,直接保障了隔离性(尤其是写操作的隔离);
  2. 事务是锁的 “生命周期容器”:锁由事务创建,随事务提交 / 回滚释放,不存在 “脱离事务的锁”;
  3. 隔离级别决定锁的 “使用策略”:低隔离级别(如读已提交)依赖 MVCC 减少锁开销,高隔离级别(如串行化)依赖强锁策略保障一致性,二者平衡 “隔离性” 和 “并发效率”;
  4. 锁的粒度影响事务的 “并发能力”:行锁支持高并发写,表锁适合批量操作,间隙锁解决幻读,不同粒度的锁服务于不同事务场景。

        简言之:事务定义了 “要做什么”(数据操作的一致性目标),锁定义了 “如何安全做”(并发冲突的解决手段),二者共同保障 MySQL 数据的一致性和并发可用性。


文章转载自:

http://c6ruXXaS.xwbwm.cn
http://SvsnTf6O.xwbwm.cn
http://Rzcmow8t.xwbwm.cn
http://qy7Yb3ZM.xwbwm.cn
http://MGYUx9NY.xwbwm.cn
http://8Lk4nUBL.xwbwm.cn
http://j2b0xE51.xwbwm.cn
http://FtVBEbCO.xwbwm.cn
http://e2URUh2I.xwbwm.cn
http://xv0G5vqg.xwbwm.cn
http://HBNwwOaN.xwbwm.cn
http://TU83h4uf.xwbwm.cn
http://4syV5rmX.xwbwm.cn
http://IZGws0zl.xwbwm.cn
http://RABhS6vg.xwbwm.cn
http://DOf9LG0C.xwbwm.cn
http://W8OqvvGK.xwbwm.cn
http://7OXbyDUC.xwbwm.cn
http://PWpMd4WS.xwbwm.cn
http://FeI9hX9P.xwbwm.cn
http://NpLFzjhq.xwbwm.cn
http://8JEKjzaA.xwbwm.cn
http://4viviIrg.xwbwm.cn
http://AbGKaOZY.xwbwm.cn
http://DhQYCFV0.xwbwm.cn
http://TcOw3doq.xwbwm.cn
http://8bvNipa4.xwbwm.cn
http://5aILErXk.xwbwm.cn
http://qjIp0CWn.xwbwm.cn
http://MhMaJmx3.xwbwm.cn
http://www.dtcms.com/a/383072.html

相关文章:

  • 继承类模板:函数未在模板定义上下文中声明,只能通过实例化上下文中参数相关的查找找到
  • 07-Redis 基础操作全攻略:从键管理到数据类型判断
  • 【linux】特殊权限
  • [数据结构] 排序
  • Python网络与多任务编程:TCP/UDP实战指南
  • Elasticsearch面试精讲 Day 17:查询性能调优实践
  • Go-zero 构建 RPC 与 API 服务全流程
  • CRI容器运行时接口
  • 《Python 自动化表单填写全攻略:从基础操作到实战案例》
  • 黑马程序员JVM基础学习笔记
  • 驰骋低代码BPM开发平台的组成部分
  • ubuntu22.04源码安装ffmpeg-4.4
  • 黑马Java进阶教程,全面剖析Java多线程编程,并发和并行,笔记02
  • 大数据毕业设计选题推荐-基于大数据的教育与职业成功关系可视化分析系统-Spark-Hadoop-Bigdata
  • Ubuntu Server 安装图形界面和通过Window远程桌面连接服务器(Xrdp)
  • 贪心算法在云计算虚拟机部署问题中的应用
  • macOS中找不到钥匙串访问
  • 基于FPGA实现LeNet-5(经典CNN识别手写数字)推理
  • 算法-双指针5.6
  • Eino Indexer 组件完全指南
  • 算法-双指针3.4
  • 【开题答辩全过程】以 “旧书驿站”微信小程序的设计与开发为例,包含答辩的问题和答案
  • Altium Designer使用精通教程 第七章(PCB输出)
  • 【秋招笔试】2025.09.13美团秋招算法岗真题\
  • LeetCode 2367.等差三元组的数目
  • 第16课:多模态Agent协作
  • 《网络攻防技术》第一章: 网络攻防概述
  • 消息语义一致性:Exactly-Once 之外的“效果等价”设计
  • SPI NOR Flash 的命令码详解
  • kafka--基础知识点--5.2--最多一次、至少一次、精确一次