禅与计算机 禅与计算机
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Redis

  • MySQL

    • MySQL基础知识点小结
    • Linux环境下MySQL部署安装
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南:深入探秘关键知识点
    • 解读MySQL Explain关键字:优化查询执行计划的实用指南
    • 深入剖析 MySQL 某条执行过程
    • 探秘 MySQL 锁:原理与实践
      • 写在文章开头
      • 详解MySQL锁原理
        • 详解共享锁和排他锁
        • 详解意向锁
        • 详解表级锁
        • 详解行级锁
        • 行级锁实际使用示例
        • 表级锁示例
        • 行级锁使用的注意事项
        • InnoDB有哪几类锁
        • 可重复读如何避免幻读
        • 详解间隙锁
        • 详解悲观锁和乐观锁
        • 当前读和快照读的区别
      • 详解MySQL中死锁问题
        • 详解定位事务各种锁的几张表
        • (实践)线上定位MySQL死锁与解决思路
      • 参考
    • 聊一个MySQL插入死锁问题
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL多版本并发控制MVCC中的运用
    • MySQL二进制日志binlog核心知识点小结
    • MySQL高效插入数据的最佳实践
    • 提升 MySQL 批量更新效率的底层原理与优化策略
    • MySQL分页查询优化指南
    • MySQL LEFT JOIN 性能优化策略
    • MySQL流式查询的奥秘与应用解析
    • 主键自增是否会降低数据库insert性能
    • 内网环境MySQL操作非正常耗时问题排查小结
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
    • 仿MyBatis-Plus实现跨数据源事务
  • ElasticSearch

  • StarRocks

  • 数据库
  • MySQL
sharkchili
2022-12-14
目录

探秘 MySQL 锁:原理与实践

# 写在文章开头

在当今数字化的时代,数据库管理系统的重要性不言而喻,而 MySQL 作为广泛应用的数据库之一,更是有着举足轻重的地位。在 MySQL 的复杂世界中,锁机制宛如一把关键的钥匙,它既是保障数据一致性和完整性的坚实卫士,也是影响数据库性能和并发处理能力的重要因素。当我们深入探索 MySQL 的领域时,不得不将目光聚焦于这看似神秘却又至关重要的锁。它究竟是如何运作的?有哪些不同的类型和特点?又如何在各种业务场景中发挥着关键作用?让我们一同开启这场关于 MySQL 锁的探索之旅,逐步揭开它的神秘面纱,去洞悉它背后的深刻原理和广泛应用,为我们更好地驾驭 MySQL 数据库奠定坚实基础。

注意:本文所有知识点都是从MySQL8.0版本进行讨论,针对5.7版本笔者会在特定知识点中点出区别。

Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 详解MySQL锁原理

# 详解共享锁和排他锁

共享锁(Share Lock,S 锁):又称读锁,进行读取操作时会上的锁,当前事务上读锁期间,其他事务也可以上读锁进行数据读,这也就是为什么读锁叫做共享锁的原因:

排他锁(Exclusive Lock,X 锁):又称写锁,进行修改操作前就需要上一把X锁,上了写锁的数据,其他事务则无法上读锁或者写锁,以保证写入操作的互斥性避免并发安全问题,所以写锁也叫排他锁:

有了上述基础,我们针对x锁对应delete和update操作进行一定的拓展,当事务进行delete的操作时,对应的步骤为:

  1. 定位要删除的数据的B+树。
  2. 对其上X锁。
  3. 上锁成功后将该位置标志位delete mark。
  4. 提交事务。

可以看到删除操作本质就是定位、标记、删除对应3个步骤,而且删除也并非实际意义上的删除,而是标记删除。

针对update操作,我们可以从以下3个维度探讨:

  1. 普通更新,即更新的字段物理空间不会变化,例如update tb set age=19 where id=1,该操作操作和上述操作差不多,定位到B+树上的数据后上X锁,并进行修改操作:

  1. 更新可变字段,假设我们基于主键更新某个varchar字段,例如update tb set name='aaaaaaaaaaaaaa' where id=1,将name由varchar(1)更新为varchar(14),那么对应的操作就是定位到数据后上X锁,将数据删除(这里的删除就是将记录移动到垃圾链表),然后执行insert操作。
  2. 更新主键,该操作因为会修改b+树,在定位到数据上X锁之后,先按照delete的方式将数据删除,然后再执行insert操作即可。

需要了解的是MySQL在进行读写操作为保证并发性能并非一定会用到读写锁,在可重复读和读已提交两个级别下,由于mvcc机制的存在,所以MySQL事务的读操作都是基于readview进行数据查询的。关于mvcc的概念,感兴趣的读者可以参考笔者这篇文章:https://mp.weixin.qq.com/s/30KsjO00FWUfHNLHyB1nRA (opens new window)

# 详解意向锁

假如我们要上全表锁,我们就必须知道这张表有没有上过读锁或者写锁的行级锁,常规做法是一行一行遍历过去看看,针对大表而言,这种全表扫的效率是非常低的。

意向锁就是用于解决这个问题的,在事务需要上读锁(S锁)或者写锁(X锁)前,首先必须取得意向锁,这样某些事务需要上全表锁时,只需要看看有没有事务持有意向锁即可:

需要补充的是,意向锁由数据引擎自行维护,用户是无法操作的。

说完意向锁的作用,我们就可以再来聊聊意向锁的种类,意向锁分为意向共享锁和意向排他锁:

  1. 意向共享锁(Intention Shared Lock,IS 锁):当事务需要上S锁时,就需要先尝试获取IS锁。
  2. 意向排他锁(Intention Exclusive Lock,IX 锁):当事务需要针对某条数据上X锁的时候,就需要先上一把IX锁。

而IS和IX之间互相兼容,彼此不互斥,例如:一个事务上了IS,其他事务同样可以上IS和IX,因为IS本质就是一个共享读锁,某个事务持有这个IS锁之后上的可能是id为1的读锁。不影响其他事务上IS或IX后对id为2的数据上X锁:

本质上来说IS和IX锁都是表级锁,它们主要是解决在事务上S锁或者X锁前意向询问来避免扫表的开销,所以彼此之间是兼容的。

接下来我们从表级锁的角度探讨以下意向锁和读写锁之间的关系,假设我们的事务需要上IS锁之后针对表再上S表级锁,此时,我们就需要查看是否有事务上了IX锁,如果有则说明有事务正在进行写操作,此时我们的S表级锁操作就会阻塞:

同理假设我们的尝试IX锁进行修改操作,需要针对全表上X锁,此时我们就需要检查是否有其他事务上了IS或者IX以确定是否存在数据操作,如果有则阻塞等待,这就是IS、IX锁对于数据读写操作的巧妙设计:

# 详解表级锁

表级锁(table-level locking)即可每一次操作时,锁的是整张表,锁的粒度大,上锁速度快,开销低,(取决于数据量)一旦某个事务上了表级锁,那么其他事务就无法再上行级锁或者表锁,这也就意味着高并发场景下性能非常差:

如下所示,这条SQL语句查询上的就是表级锁:

SELECT * FROM s1   for update;
1

这一点我们可以通过查看performance_schema.data_locks表印证这一点,可以看到这个事务上的是IX意向写锁,并将表中的所有的记录即都上了record写锁:

# 详解行级锁

行级锁(table-level locking)锁的粒度相对小一些,是针对索引字段加锁,锁的是选定的行数据,相比前者上锁速度会慢一些,因为需要定位到当前行才能锁定,并且因为粒度和逻辑设计问题有可能会导致死锁,但是对于高并发多事务会相对友好一些:

对应我们给出行级锁的使用示例:

SELECT * FROM s1 WHERE id=1 for update;
1

通过performance_schema.data_locks表,可以看到这条该事务上X锁前上了一把IX锁之后,针对这条记录上了X,REC_NOT_GAP即上了一把行级锁,但是不锁住间隙:

注意:我们上文所讨论的都是针对innodb这个存储引擎,如果是MyISAM这个存储引擎仅仅支持表级锁,而InnoDB支持行级锁。

# 行级锁实际使用示例

我们先给出行锁的使用示例,首先创建一张测试表,注意id被设置为主键是自带索引的:

drop  table user;

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;

1
2
3
4
5
6
7
8
9

然后插入几条测试数据:

insert into	`user`(username,	age)values
 ('tom',23),
('joey',22),
('James',21),
('William',20),
('David',24);
1
2
3
4
5
6

关闭事务自动提交,并确认:

-- 关闭事务自动提交
set  autocommit = 0;

-- 查看自动提交是否生效
show VARIABLES like 'autocommit';
1
2
3
4
5

此时,在窗口键入一下SQL进行查询,可以看到笔者用了for update对id为1的数据上了排他锁。


begin;
select * from `user` u where id=1 for update ;
1
2
3

此时我们再开一个排他锁查询,可以看到事务阻塞:

begin;
select * from `user` u where id=1 for update ;
1
2

由此可知,使用排他锁对索引列上锁时,其他排他锁是无法操作对应数据行的:

补充一个联合索引的行级锁使用示例,基于上述表格我们创建一个联合索引:

create index index_username_age on user(username,age);

1
2

开启一个事务进行查询

begin;
select * from user where username ='tom' and age=23  for update ;
1
2

此时另一个事务进行相同查询会阻塞,走不相同的查询条件不会阻塞,说明联合索引也是走行级锁:

begin;
select * from user where username ='tom' and age=23  for update ;
1
2

我们通过performance_schema.data_locks表可以看到,第一个事务针对tom数据上了一把行级写锁:

# 表级锁示例

上文提到,只要不走索引的查询锁定的都是整张表,所以我们使用age对应22的SQL查询语句上排他锁:

begin;
select * from user where age=20 for update;
1
2

再打开另一个窗口就会发现,窗口被阻塞

begin;
select * from user where age=22 for update ;
1
2

很明显因为没有命中索引所以无法通过索引方式进行定位,所以上了表级锁,这一点我们也可以通过information_schema.INNODB_TRX表查看,可以看到第一个事务将所有数据行都上了锁:

# 行级锁使用的注意事项

我们都知道行级锁锁的是索引字段,而表级锁锁的是非索引字段,这就意味着如果我们进行update或者delete操作 (这两个操作会上写锁互斥的,后文会说明)时where条件没有命中唯一索引或者索引失效的话,就会上表级锁,进而出现性能问题。

当然了,有时候MySQL优化器也会不走索引,例如范围索引检索范围区间超过30%,优化器就会走全表扫描,那就无能为力了。

# InnoDB有哪几类锁

  1. 记录锁(Record Lock):这个锁锁定的是单个记录行上的锁。
  2. 间隙锁(Gap Lock):这个锁锁定的是一个范围,例如查找id>21的用户,那么间隙锁锁定的就是大于21的记录,不包括21本身。
  3. 临建锁(Next-key Lock):这个锁我们可以理解为是记录锁和间隙锁的综合,它可以保证当前锁定的记录及其间隙都上锁,这个锁可以保证可重复读场景下事务读避免幻读问题,例如我们数据正在读取id为8的数据,针对该锁上一把Next-key Lock可以阻塞当前数据及其前后区间被其他事务操作导致幻读:

# 可重复读如何避免幻读

可重读读避免幻读的方式有两种:

  1. 快照读(一次性非锁定读):这种方式就是通过mvcc的方式仅仅在启动时创建一个readView确保不会出现幻读。
  2. 当前读(一次性锁定读):这种方式就是通过临建锁,避免新的记录插入从而避免幻读的情况发生。

具体可以参考笔者的这篇文章:https://mp.weixin.qq.com/s/30KsjO00FWUfHNLHyB1nRA (opens new window)

# 详解间隙锁

上文说过,间隙锁就是在范围查询时对索引项上锁,但不包括范围本身的一种锁,这种机制在RR这个隔离级别可以一定程度上避免幻读,注意是一定程度上。

对此我们不妨举个例子:

首先我们创建一个用户表,并对age加个索引:

drop  table user;

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;


create index age_index on user(age);
1
2
3
4
5
6
7
8
9
10
11

然后插入测试数据:

insert	into	`user`(username,	age)values ('tom',23),('joey',22),('James',21),('William',20),('David',24);

1
2

由于MySQL默认隔离级别为RR,所以我们开启一个窗口设置关闭自动提交,并查看其是否生效

-- 关闭事务自动提交
set  autocommit = 0;

-- 查看自动提交是否生效
show VARIABLES like 'autocommit';

1
2
3
4
5
6

若生效,我们则输入一个begin,并进行一个范围查询,搜索大于24范围的数据:


begin;
select * from user where age >24 for update;
1
2
3

当我们在开启一个新的窗口并进行插入操作时可以发现,操作被阻塞了:

begin;
insert into	`user`(username,	age)values ('tom',26);
1
2

因为年龄上了索引,所以查询时走了范围索引,从performance_schema.data_locks可以看出该操作针对id为5、10这两条年龄为24的数据都上了行级锁和间隙锁,导致数据插入失败:

# 详解悲观锁和乐观锁

悲观锁就我们上面所说的互斥锁,它认为自己每次拿到的数据都很可能被人修改,通过上锁确保互斥性避免数据一致性问题。在MySQL中select...for update,insert,update、delete语句用的都是用排他锁实现悲观锁。

而乐观锁则是一种业务锁,通过用户手动对表增加一个版本号的字段来解决并发数据正确性问题,如下图所示,某个时间点两个相同的事务读取到相同版本号的当行数据,彼此都执行更新逻辑,为了保证并发更新保证数据准确性,我们就需要通过版本号确保自己更新的数据是最新数据,如下图所示,左边的更新SQL最先执行,这就使得右边的更新失败了,这样右边的事务就知道自己更新条件数据已过期,就会修改版本号再次进行更新。

# 当前读和快照读的区别

当前读也就是我们常说的一致性锁定读,当前读发生在读已提交(RC)或者可重复读(RR)这两个隔离级别下,我们使用的select使用的就是快照读:

  1. 若在RC这个隔离级别下,用户每次进行读操作时,都会创建一个readView,然后通过这个readView获取数据。
  2. 若在RR这个隔离级别下,仅仅在启动事务时创建一个readVew,后续无论其他事务无论修改用户读取的数据,用户都只会读取当前readView的数据,这就是为什么RR可以保证可重入读。

而当前读(一致性锁定读)则基于S锁或者X锁实现的一种读取最新数据,对应的select语句如下:

SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE

1
2
3

当然,我们的insert、update、delete语句也是使用当前读。

# 详解MySQL中死锁问题

# 详解定位事务各种锁的几张表

在正式演示死锁定位与排查思路之前,我们先简单介绍几张比较重要的表,首先是INNODB_TRX 这张表,它会记录当前活跃事务所持有的锁的情况:

SELECT * FROM information_schema.INNODB_TRX it ;
1

如下图,可以看到我们567584这个事务,这里我们着重查看trx_tables_locked、trx_lock_structs、trx_rows_locked三个字段,其含义分别是:

  1. trx_tables_locked:当前事务对几张表上锁,以本条数据为例就上了一把锁。
  2. trx_rows_locked:标识当前事务锁定几行数据,下图表示当前事务锁定了一行数据。
  3. trx_lock_structs:当前事务生成几个锁的结构体,显示为2,即生成两个锁的结构体。

我们再来看看data_locks表(对应MySQL5.7版本表明为innodb_locks),这张表在MySQL中活跃事务的上锁情况:

 select * from performance_schema.data_locks;
1

如下图,可以看到567834事务的线程号、事件id以及这个事务在tb_1表上了一把IX意向读锁:

最后再来看看 data_lock_waits表(对应MySQL5.7是innodb_waits表),这张表就比较重要了,它代表了当前事务中处于等待锁状态的事务情况:


select * from performance_schema.data_lock_waits;
1
2

如下图,可以看到本文的567585事务正在等待567584的事务的锁:

# (实践)线上定位MySQL死锁与解决思路

接下来我们就基于一个简单的例子来掩饰一下如何定位死锁问题,我们都知道for update上的是写锁,这意味着一旦上了X锁的数据,其他事务就无法针对该数据上S锁或者X锁:

如下图这个说明,假设的我们的事务1先针对id为1的值上了一把写锁,对应事务的SQL如下:

begin;
SELECT * FROM  tb_1 t WHERE id =1 for UPDATE ;
SELECT * FROM  tb_1 t WHERE id =2 for UPDATE ;
1
2
3

同理第二个事务现针对id为2的数据上写锁,在针对id为1的数据上写锁,由此双方循环等待,造成死锁

begin;
SELECT * FROM  tb_1 t WHERE id =2 for UPDATE ;
SELECT * FROM  tb_1 t WHERE id =1 for UPDATE ;
1
2
3

接下来我们就基于上述所说的3张表进行死锁的问题的定位,首先我们查看INNODB_TRX可以看到我们本次SQL的事务号为567585它处于锁等待状态,可以看到它正在执行的SQL语句以及上锁的信息

然后我们到data_locks表查看当前数据库的锁情况,这个事务正在等待X锁和REC_NOT_GAP锁,说明这个事务存在死锁:

最后再到data_lock_waits可以看到567585的事务等待567584的事务

明确定位了两个事务的,查看innodb 状态信息定位到这两个事务号的执行执行语句:

show engine innodb status;
1

最终,可以看到处于等待的事务567585锁等待的事务567584所执行的SQL语句,很明显是因为上了同一个行级锁造成事务567585等待造成死锁:

针对死锁问题这个问题,我们先得说说造成死锁的4个条件:

  1. 互斥
  2. 不可剥夺
  3. 请求和保持条件
  4. 锁之间构成环路

所以MySQL解决死锁的方式大抵有以下几种:

  1. 每个事务按照顺序到表中上锁(破坏环路条件)。
  2. 将大事务拆小。
  3. 逻辑上要求事务必须一次性取得两张表的锁才能操作数据。
  4. 降低隔离级别,例如将RR级别降低为RC避免上间隙锁确保降低发生死锁的概率。

我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 参考

MySQL常见面试题总结:https://javaguide.cn/database/mysql/mysql-questions-01.html#mysql-如何存储-ip-地址 (opens new window)

MySQL锁相关:https://juejin.cn/post/6844903821546618888#heading-18 (opens new window)

Mysql 8查看并修改事务隔离级别:https://blog.csdn.net/q283614346/article/details/103938542 (opens new window)

MySQL间隙锁、Next-Key Lock主要知识点:https://www.jianshu.com/p/d5c2613cbb81 (opens new window)

《MySQL是怎样运行的:从根儿上理解MySQL》

MySQL的数据锁表(data_locks 表):https://blog.csdn.net/jkzyx123/article/details/135848317 (opens new window)

编辑 (opens new window)
上次更新: 2026/03/26, 01:05:31
深入剖析 MySQL 某条执行过程
聊一个MySQL插入死锁问题

← 深入剖析 MySQL 某条执行过程 聊一个MySQL插入死锁问题→

最近更新
01
基于EasyExcel实现高效导出
03-25
02
从开源框架中学习那些实用的位运算技巧
03-25
03
浅谈分布式架构设计思想和常见优化手段
03-25
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×