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

MySQL问题7

MySQL中的锁类型

在这里插入图片描述

1. 粒度锁

  • 行级锁

    • 针对数据表中的某一行或多行加锁
    • 并发度高,但开销较大
  • 表级锁

    • 针对整张表加锁
    • 并发度低,但开销小、加锁快

2. 意向锁

  • 意向锁

    • 用于表明事务即将在某些行上加共享锁或排他锁
    • 作用:快速判断表是否可以加表级锁

3. 读写锁

  • 共享锁(S 锁)

    • 允许事务读取数据,但不能修改
    • 多个事务可同时持有同一行的共享锁
  • 排他锁(X 锁)

    • 允许事务对数据进行读写
    • 其他事务不能再获取该数据的共享锁或排他锁

4. 元数据锁(MDL)

  • 元数据锁

    • 用于保护表的结构定义
    • 例如:防止 DDL 与 DML 并发冲突

5. InnoDB 特有锁

  • 间隙锁(Gap Lock)

    • 锁定索引记录之间的“间隙”
    • 防止其他事务在间隙中插入数据
  • 临键锁

    • 行锁 + 间隙锁的组合
    • 解决可重复读隔离级别下的幻读问题
  • 插入意向锁

    • 表示事务准备在某个间隙插入数据
    • 多个事务可以同时持有,不互相冲突
  • 自增锁

    • 针对自增字段的特殊锁
    • 保证多事务同时插入时自增值的唯一性和有序性

MySQL事务的二阶段提交

  • redo log:保证崩溃恢复(crash recovery),属于 InnoDB 层。
  • binlog:保证数据一致性和主从复制,属于 MySQL Server 层。

保证这两份日志的数据一致性,MySQL 引入了 二阶段提交
在这里插入图片描述

1、为什么需要二阶段提交?

只写一份日志,可能会出现以下问题:

  • 只写 redo log,不写 binlog
    → 主从复制时,从库无法得到这次事务。

  • 只写 binlog,不写 redo log
    → 主库宕机恢复后,数据丢失,但 binlog 里却存在这条记录,主从数据不一致。

必须保证 redo log 和 binlog 的写入结果要么同时成功,要么同时失败。
这就是 二阶段提交 的目的。


2、二阶段提交的流程

事务提交时,日志写入分为 prepare 阶段commit 阶段

  1. prepare 阶段

    • InnoDB 写入 redo log 的 prepare 状态,表示事务即将提交,但还没提交。
    • redo log 落盘,保证即使宕机,数据也能恢复。
  2. 写 binlog

    • MySQL Server 层写入 binlog。
    • 并将 binlog 刷盘。
  3. commit 阶段

    • InnoDB 把 redo log 状态从 prepare 改为 commit
    • 至此,事务提交完成。
  • 二阶段提交 = redo log + binlog 的双写机制
  • 作用:保证事务在 崩溃恢复主从复制 中的一致性。
  • 关键点:先写 redo log(prepare)→ 写 binlog → redo log(commit)。

发生死锁的解决办法

1. 死锁的检测机制

在这里插入图片描述

  • 自动检测
    InnoDB 内部有 死锁检测机制(默认开启),当检测到死锁时,会选择 回滚一个代价较小的事务,让另一个事务继续执行。

    • 参数:innodb_deadlock_detect=ON
  • 超时等待
    如果检测关闭,则依赖锁等待超时机制。

    • 参数:innodb_lock_wait_timeout(默认 50 秒)。
  • kill发生死锁的语句


2. 排查死锁的方式

  • 查看最近死锁日志

    SHOW ENGINE INNODB STATUS\G
    
    • 发生死锁的事务 ID
    • 执行的 SQL
    • 加锁的情况
    • 被回滚的事务

常见的死锁日志

------------------------
LATEST DETECTED DEADLOCK
------------------------
2025-09-08 21:05:45
*** (1) TRANSACTION:
TRANSACTION 12345, ACTIVE 3 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 25, OS thread handle 140146653595200, query id 1234 localhost root
UPDATE orders SET status='done' WHERE id=100;*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 123 page no 456 n bits 72 index `PRIMARY` of table `test`.`orders` trx id 12345 lock_mode X locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 123 page no 456 n bits 72 index `PRIMARY` of table `test`.`orders` trx id 12345 lock_mode X locks rec but not gap waiting*** (2) TRANSACTION:
TRANSACTION 12346, ACTIVE 2 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 26, OS thread handle 140146653595600, query id 1235 localhost root
UPDATE orders SET status='done' WHERE id=200;*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 123 page no 456 n bits 72 index `PRIMARY` of table `test`.`orders` trx id 12346 lock_mode X locks rec but not gap
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 123 page no 456 n bits 72 index `PRIMARY` of table `test`.`orders` trx id 12346 lock_mode X locks rec but not gap waiting*** WE ROLL BACK TRANSACTION (2)

3. 死锁的常见原因

  1. 事务访问顺序不一致

    事务 A 先锁表 1 再锁表 2,事务 B 先锁表 2 再锁表 1。

  2. 长事务

    占用大量行锁,导致其他事务长时间等待。

  3. 没有索引,导致锁范围扩大

扫描范围大 → 行锁变表锁或间隙锁,引发冲突。

  1. 外键约束或级联更新

父子表之间可能导致意料之外的加锁顺序。


4. 解决死锁的方法

(1)应用层面预防

  • 统一访问顺序
    保证不同事务访问同一组资源时,顺序一致。
  • 尽量减少锁范围
    通过索引精确过滤,避免无索引全表扫描加锁。
  • 缩短事务时间
    避免长事务,及时提交,减少锁占用。
  • 分解大事务
    把一个大事务拆成多个小事务提交。

(2)数据库配置层面

  • 启用死锁检测(默认开启)
    让 InnoDB 自动选择一个事务回滚。
  • 合理设置超时时间
    innodb_lock_wait_timeout 调小,可以更快释放死锁等待。

(3)发生死锁后的处理

  • 应用重试机制
    由于 MySQL 会回滚一个事务,应用需要捕获 Deadlock found when trying to get lock 错误,然后 重试事务


文章转载自:

http://SzEieJzO.smmby.cn
http://hqViREmA.smmby.cn
http://YoDREuwq.smmby.cn
http://9OCVvU9N.smmby.cn
http://K7upEMtw.smmby.cn
http://vHx9wewD.smmby.cn
http://CPK9a9Gw.smmby.cn
http://AUTtOBtq.smmby.cn
http://zuLEHDGw.smmby.cn
http://6L9jXFnA.smmby.cn
http://WOQ6jyx6.smmby.cn
http://UFR6uSzu.smmby.cn
http://WuJyZZUH.smmby.cn
http://zUZ4lsAD.smmby.cn
http://uk1wCzF5.smmby.cn
http://qPy462hn.smmby.cn
http://VeGwjrQA.smmby.cn
http://HIsBUx52.smmby.cn
http://STVc2mH9.smmby.cn
http://99vaM03h.smmby.cn
http://ITI17nif.smmby.cn
http://vm7aZ4mc.smmby.cn
http://NlUZ7kcV.smmby.cn
http://FxkBWKoN.smmby.cn
http://ZXSiHs8K.smmby.cn
http://axiFLTTD.smmby.cn
http://oLDaE08W.smmby.cn
http://BZs6VhDG.smmby.cn
http://AbeTHO8k.smmby.cn
http://ZMPtkpLH.smmby.cn
http://www.dtcms.com/a/373891.html

相关文章:

  • Sealminer A2 224T矿机评测:SHA-256算法,适用于BTC/BCH
  • windows下安装claude code+国产大模型glm4.5接入(无需科学上网)
  • C语言与FPGA(verilog)开发流程对比
  • 5G/6G时代的智能超表面:如何重构无线传播环境?
  • 【3D图像算法技术】如何对3DGS数据进行编辑?
  • Node.js对接即梦AI实现“千军万马”视频
  • Spring Boot Banner
  • 安卓端部署Yolov5目标检测项目全流程
  • 《2025年AI产业发展十大趋势报告》四十六
  • 《普通逻辑》学习记录——普通逻辑的基本规律
  • 彻底禁用 CentOS 7.9 中 vi/vim 的滴滴声
  • [C++刷怪笼]:AVL树--平衡二叉查找树的先驱
  • [概率]Matrix Multiplication
  • 【C++】哈希表实现
  • 方法引用知识
  • gtest全局套件的测试使用
  • [硬件电路-163]:Multisim - 功能概述
  • vue集成高德地图API工具类封装
  • Elixir通过Onvif协议控制IP摄像机,ExOnvif库给视频流叠加字符
  • GEM5学习(5): ARM 架构功耗仿真
  • TCP 拥塞控制与四次挥手解析
  • Linux 进程深度解析:从底层架构到虚拟地址空间
  • 软件测试之测试分类(沉淀中)
  • 使用Postfix+Dovecot+数据库+Web界面搭建邮件服务器详细指南
  • ubuntu 安装 docker 详细步骤
  • 无外部依赖!学习这款Qt6 SSH/SFTP客户端
  • Agentic RL Survey: 从被动生成到自主决策
  • AFE和电流传感器的区别
  • 【springboot+vue】高校迎新平台管理系统(源码+文档+调试+基础修改+答疑)
  • HTTP 请求体格式详解