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

Mysql 中的锁

什么是“锁”?

  • *锁(Lock)**是数据库为保证多用户并发访问数据时,数据的一致性与完整性而采取的一种机制。

就像你在一个文档上修改,防止别人同时修改冲突,给它上锁

数据库主要有两类锁:

分类子类型简要说明
物理层锁表锁、行锁、页锁作用于数据“位置”
逻辑层锁乐观锁、悲观锁作用于“逻辑业务”,一般由程序实现

✅ 1. 表锁(Table Lock)

  • 整张表加锁,其他线程无法读写
  • 粒度大,冲突概率高,MyISAM引擎用得多
LOCK TABLES user WRITE;

✅ 2. 行锁(Row Lock)

  • 只锁住当前操作的行
  • 粒度小,性能好,InnoDB默认支持
  • 举例:
UPDATE user SET name = '张三' WHERE id = 1;

✅ 3. 乐观锁(Optimistic Lock)

  • 假设没有冲突,不加锁
  • 提交前检查“版本”或“时间戳”
  • 冲突时提示失败
  • 一般通过字段控制,如:
UPDATE table SET version = version + 1
WHERE id = 1 AND version = 3;

✅ 4. 悲观锁(Pessimistic Lock)

  • 认为有冲突,加锁保护
  • 每次读取/写入都锁住数据(阻塞其他操作)
  • InnoDB默认是悲观锁模式,如:
SELECT * FROM user WHERE id = 1 FOR UPDATE;

🔁 四、UPDATE 语句的锁行为

情况分析(基于 InnoDB 引擎):

  • 使用索引可确保行锁,否则可能锁整张表
SQL语句锁类型说明
UPDATE … WHERE id=1行锁默认加排他锁(X锁),锁住符合条件的行
UPDATE … 没有索引表锁(或间隙锁)InnoDB 尝试行锁失败时退化为表锁或意外加范围锁
事务外操作自动提交 + 加锁没有事务会立即提交释放锁
加 FOR UPDATE显式加锁同样是行锁,但常用于事务读取后锁定数据

为什么insert/update 不会锁整张表?

在使用 InnoDB 引擎 时,MySQL 默认采用的是 行级锁(Row Lock),这是它区别于 MyISAM 表锁的重要优势之一:

操作类型加锁级别说明
INSERT行锁 / 无锁通常不会锁已有数据,只是插入,几乎不会阻塞其他操作
UPDATE … WHERE id=1行锁会锁住满足条件的行(id=1),不会锁整张表
DELETE … WHERE id=1行锁同样只锁住目标行

⚠️ 但注意:

如果:

  • 没有使用索引 或
  • WHERE 语句无法命中索引

那 MySQL 可能会退化为表锁或间隙锁,这是性能隐患!

✅ 二、如果我此时在执行 DDL 操作(比如 ALTER TABLE)会发生什么?

🔒 DDL 操作(如 ALTER TABLE)一定会加表锁!

操作锁类型说明
ALTER TABLE …表锁会阻塞该表的读写,直到结构变更完成
ADD/DROP COLUMN表锁同上
CREATE INDEX(同步)表锁会阻塞写入操作(可考虑在线索引)

如果在执行:

ALTER TABLE user ADD COLUMN nickname VARCHAR(255);

此时其他连接中的以下操作会被 阻塞

SELECT * FROM user;       -- ❌ 阻塞
UPDATE user SET name='a'; -- ❌ 阻塞
INSERT INTO user ...      -- ❌ 阻塞

🚫 在该 ALTER TABLE 执行期间:

  • 任何对这张表的 读操作(SELECT * FROM user)都会被阻塞
  • 任何对这张表的 写操作(UPDATE、INSERT、DELETE)也都会被阻塞

✅ 等ALTER TABLE完成后:

这些被阻塞的操作才会依次执行,或者超时失败(取决于客户端/连接池设置的超时时间)。

🔧 解决建议(生产环境):

  • 避免高峰期执行 DDL 操作
  • 使用在线DDL工具(如 Percona 的 pt-online-schema-change、GitHub 的 gh-ost),避免阻塞业务请求

DDL的排队

Data Definition Language

  • MySQL 的 DDL 操作本质上 需要排他访问表,也就是说:

    要等到当前表上没有其他事务正在访问或占锁

🔁 举个例子:

时间操作描述
T1业务线程A执行 UPDATE user SET … WHERE id=1 并开启了事务,但没有提交占用行锁
T2你执行了 alembic upgrade,尝试 ALTER TABLE user ADD COLUMN xxxMySQL 尝试加表锁,发现表上还有事务未提交 → 被阻塞,卡住了
T3业务线程A事务迟迟没提交你这边就一直挂着
误解实际机制
“DDL 最优先,其他操作应该等它”❌ 错!DDL 也要等现有事务释放表相关锁
“表被频繁更新,DDL 就会失败”✅ 是的,频繁操作造成的锁占用会阻塞 DDL
“表结构改不动是因为 MySQL 不稳定”❌ 是因为 DDL 拿不到锁

✅ 你的 update 没写事务,为什么还是会“加锁”?

因为InnoDB 默认使用“自动提交模式”

也就是说,如果你没有显式写 BEGIN 或 START TRANSACTION,那么:

UPDATE user SET name = '张三' WHERE id = 1;

这条语句实际上会被 MySQL 当作:

START TRANSACTION;
UPDATE user SET name = '张三' WHERE id = 1;
COMMIT;

所以虽然你“看起来没用事务”,InnoDB 内部还是执行了一个隐式事务

✅ 这个隐式事务行为的结果是:

UPDATE 时,会加 行锁(InnoDB 默认)

因为你没显式控制事务,所以 语句一执行完就自动提交,锁也就立刻释放了

因此,大多数情况下你看不到锁阻塞的现象

相关文章:

  • 直流电机 pwm 调速
  • 人工智能数学基础实验(二):奇异值分解(SVD)-图像处理
  • LangChain4j 项目实战——idea快捷键搜索
  • Scratch游戏 | 枪战游戏
  • 自动化安全脚本学习
  • 动态规划(6)下降路径最小值
  • C++ gtest单元测试
  • golang逃逸分析
  • AI 集成
  • C/C++ 结构体:. 与 -> 的区别与用法及其STM32中的使用
  • 基于MATLAB实现传统谱减法以及两种改进的谱减法(增益函数谱减法、多带谱减法)的语音增强
  • mysql:MVCC机制
  • leetcode 39. Combination Sum和40. Combination Sum II
  • 人工智能100问☞第32问:什么是迁移学习?
  • 机器学习课程设计报告 —— 基于口红数据集的情感分析
  • 【免杀】C2免杀技术(九)DLL注入前置篇
  • 事务操作语句
  • 美团2025年校招笔试真题手撕教程(三)
  • [Linux]磁盘分区及swap交换空间
  • React整合【ECharts】教程002:折线图的构建和基本设置
  • 做直发网站/seo百度发包工具
  • 金阳建设集团网站/武汉网站开发公司
  • pub域名怎么做网站/郑州网站制作公司
  • 中国最好的网站建设公司/免费的seo网站下载
  • 郑州做网站要多少钱/色盲怎么治疗
  • 有没有个人做试卷网站的/佛山市人民政府门户网站