【MySQL进阶之路 | 高级篇】表级锁之S锁,X锁,意向锁

news2024/12/30 3:10:58

1. 从数据操作的粒度划分:表级锁,页级锁,行锁

为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗资源的事情(涉及获取、检查、释放锁等动作)。因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了‘锁粒度’的概念。

对一条记录加锁影响的也只是这条记录而已,我们就说这个锁的粒度比较细;其实一个事务也可以在表级别进行加锁,自然就被称之为表级锁或者表锁,对一个表加锁影响整个表中的记录,我们就说这个锁的粒度比较粗。锁的粒度主要分为表级锁、页级锁和行锁。

1.1 表锁(Table Lock)

该锁会锁定整张表,它是MySQL中最基本的锁策略,并不依赖于存储引擎(不管你是MysQL的什么存储引擎,对于表锁的策略都是一样的),并且表锁是开销最小的策略((因为粒度比较大)。由于表级锁一次会将整个表锁定,所以可以很好的避免死锁问题。当然,锁的粒度大所带来最大的负面影响就是出现锁资源争用的概率也会最高,导致并发率大打折扣。

a. 表级别的S锁,X锁

在对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,InnoDB存储引擎是不会为这个表添加表级别的S锁或者x锁的。在对某个表执行一些诸如ALTER TABLE、DROP TABLE这类的DDL语句时,其他事务对这个表并发执行诸如SELECT、INSERT、DELETE、UPDATE的语句会发生阻塞。同理,某个事务中对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,在其他会话中对这个表执行DDL语句也会发生阻塞。这个过程其实是通过在server层使用一种称之为元数据锁(英文名: Metadata Locks,简称MDL)结构来实现的。

一般情况下,不会使用InnoDB存储引擎提供的表级别的S锁和X锁。只会在一些特殊情况下,比方说崩溃恢复过程中用到。比如,在系统变量autocommit=0,innodb_table_locks = 1时,手动获取InnoDB存储引擎提供的表t的S锁或者x锁可以这么写:

  • LOCK TABLES t READ : InnoDB存储引擎会对表t加表级别的S锁。
  • LOCK TABLES t WRITE: InnoDB存储引擎会对表t加表级别的X锁。

不过尽量避免在使用InnoDB存储引擎的表上使用LOCK TABLES这样的手动锁表语句,它们并不会提供什么额外的保护,只是会降低并发能力而已。InnoDB的厉害之处还是实现了更细粒度的行锁,关于InnoDB表级别的S锁和X锁大家了解一下就可以了。

我们可以在MISAM存储引擎的表中测试表级锁:

# 添加表共享读锁
lock tables mylock read;

# 查看锁
show open  tables where ...

# 释放锁
unlock tables;

小结:

MyISAM在执行查询语句前,会给涉及的所有表加读锁,在执行增删改操作前,会给涉及的表加写锁。Innodb存储引擎是不会为这个表添加表级别的读锁或者写锁的。

b. 意向锁

InnoDB支持多粒度锁(multiple granularity locking),它允许行级锁与表级锁共存,而意向锁就是其中的一种表锁。

  1. 意向锁的存在是为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。
  2. 意向锁是一种不与行级锁冲突表级锁,这一点非常重要。
  3. 表明“某个事务正在某些行持有了锁或该事务准备去持有锁

意向锁分为两种:

  • 意向共享锁(intention shared lock,IS):事务有意向对表中的某些行加共享锁(s锁)
--事务要获取某些行的S锁,必须先获得表的IS 锁。

SELECT column FROM table ... LOCK IN SHARE MODE;

意向排他锁(intention exclusive lock, lX)︰事务有意向对表中的某些行加排他锁(x锁)
 

--事务要获取某些行的×锁,必须先获得表的工X锁。

SELECT column FROM table ... FOR UPDATE;

即:意向锁是由存储引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享/排他锁之前,InooDB会先获取该数据行所在数据表的对应意向锁。

意向锁要解决的问题

现在有两个事务,分别是T1和T2,其中T2试图在该表级别上应用共享或排它锁,如果没有意向锁存在,那么T2就需要去检查各个页或行是否存在锁;如果存在意向锁,那么此时就会受到由T1控制的表级别意向锁的阻塞。T2在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁。简单来说就是给更大一级别的空间示意里面是否已经上过锁。

在数据表的场景中,如果我们给某一行数据加上了排它锁,数据库会自动给更大一级的空间,比如数据页或数据表加上意向锁,告诉其他人这个数据页或数据表已经有人上过排它锁了,这样当其他人想要获取数据表排它锁的时候扌只需要了解是否有人已经获取了这个数据表的意向排他锁即可。

  • 如果事务想要获得数据表中某些记录的共享锁,就需要在数据表上添加意向共享锁。
  • 如果事务想要获得数据表中某些记录的排他锁,就需要在数据表上添加意向排他锁。这时,意向锁会告诉其他事务已经有人锁定了表中的某些记录。

我们需要知道意向锁之间的兼容互斥性,如图:

即意向锁之间是相互兼容的,虽然意向锁和自家兄弟互相兼容,但还是它会与普通的排他锁/共享锁互斥。

这里的排他锁/共享锁指的都是表锁,意向锁不会与行级的共享/排他锁互斥。

结论:
  1. InnoDB支持多粒度锁,特定场景下,行级锁可以与表级锁共存。
  2. 意向锁之间互不排斥,但除了IS与S兼容外,意向锁会与共享锁/排他锁互斥。
  3. IS,IX是表级锁,不会和行级的X锁和S锁发生冲突。只会和表级的X锁,S锁发生冲突。
  4. 意向锁在保证并发性的前提下,实现了行锁和表锁共存且满足事务隔离性的要求。
c. 自增锁(AUTO-INC锁)

在使用MySQL过程中,我们可以为表的某个列添加AUTO_INCREAMENT属性。

MySQL中采用了自增锁的方式来实现,AUTO-INC锁是当向使用含有AUTO_INCREMENT列的表中插入数据时需要获取的一种特殊的表级锁,在执行插入语句时就在表级别加一个AUTO-INC锁,然后为每条待插入记录的AUTO_INCREMENT修饰的列分配递增的值,在该语句执行结束后,再把锁释放掉。一个事务在持有AUTO-INC锁过程中,其他事务的插入语句都要被阻塞,可以保证一个语句中分配的递增的值是连续的。也正因为如此其并发性能不高。当我们向有一个auto_increament关键字的主键插入值时,每条语句都要对这个表锁进行竞争,这样的并发潜力其实是很低下的,所以innodb通过innodb_autoinc_lock_mode的不同取值来提供不同的锁定机制,来显著提高sQL语句的可伸缩性和性能。

innodb_autoinc_lock_mode有三种取值,分别对应与不同锁定模式:

  • (1) innodb_autoinc_lock_mode = e(“传统"锁定模式)

在此锁定模式下,所有类型的insert语句都会获得一个特殊的表级AUTO-INc锁,用于插入具有AUTO_INCREMENT列的表。这种模式其实就如我们上面的例子,即每当执行insert的时候,都会得到一个表级锁(AUTO-INC锁),使得语句中生成的auto_increment为顺序,且在binlog中重放的时候,可以保证master与slave中数据的auto_increment是相同的。因为是表级锁,当在同一时间多个事务中执行insert的时候,对于AUTO-INC锁的争夺会限制并发能力。

  • (2) innodb_autoinc_lock_mode = 1(“连续"锁定模式)

在这个模式下,“bulk inserts"仍然使用AUTO-INC表级锁,并保持到语句结束。这适用于所有INSERREPLACE ...SELECT和LOAD DATA语句。同一时刻只有一个语句可以持有AUTO-INC锁。对于"“Simple inserts”(要插入的行数事先已知),则通过在mutex(轻量锁)的控制下获得所需数量的自动递增值来避免表级AUTO-INC锁,它只在分配过程的持续时间内保持,而不是直到语句完成。不使用表级AUTO-INC锁,除非AUTO-INC锁由另一个事务保持。如果另一个事务保持AUTO-INC锁,则Ssimple inserts"等待AUTO-INC锁,如同它是一个“bulk inserts"。

  • (3 ) innodb_autoinc_lock_mode = 2(“交错"锁定模式)

从MySQL 8.o开始,交错锁模式是默认设置。在这种锁定模式下,所有类INSERT语句都不会使用表级AUTO-INC锁,并且可以同时执行多个语句。这是最快和最可扩展的锁定模式,但是当使用基于语句的复制或恢复方案时,从二进制日志重播SQL语句时,这是不安全的。在此锁定模式下,自动递增值保证在所有并发执行的所有类型的insert语句中是唯一且单调递增的。但是,由于多个语句可以同时生成数字(即,跨语句交叉编号),为任何给定语句插入的行生成的值可能不是连续的。如果执行的语句是"simple inserts”,其中要插入的行数已提前知道,除了“Mixed-mode inserts"之外,为单个语句生成的数字不会有间隙。然而,当执行“bulk inserts"时,在由任何给定语句分配的自动递增值中可能存在间隙。

d. 元数据锁(MDL)

MySQL5.5引入了meta data lock,简称MDL锁,属于表锁范畴。MDL的作用是,保证读写的正确性。比如,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,增加了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。

因此,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁.

读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性,解决了DML和DDL操作之间的一致性问题。不需要显式使用,在访问一个表的时候会被自动加上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1953158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端开发:HTML与CSS

文章目录 前言1.1、CS架构和BS架构1.2、网页构成 HTML1.web开发1.1、最简单的web应用程序1.2、HTTP协议1.2.1 、简介1.2.2、 http协议特性1.3.3、http请求协议与响应协议 2.HTML概述3.HTML标准结构4.标签的语法5.基本标签6.超链接标签6.1、超链接基本使用6.2、锚点 7.img标签8.…

【网络安全的神秘世界】文件包含漏洞

🌝博客主页:泥菩萨 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 一、概述 文件包含:重复使用的函数写在文件里,需要使用某个函数时直接调用此文件,而无需再…

【学习日记】函数调用 和 全局变量 如何实现 位置无关码

问题来源 在 I.MX6ull 的启动流程中,u-boot会将自身从内存一开始的位置拷贝到其他位置,以便给linux留出内存空间,防止 u-boot被覆盖如果代码中包含直接引用其链接时地址的指令,那么当代码被移动到新的地址时,这些引用…

聊聊RNNLSTM

RNN 用于解决输入数据为,序列到序列(时间序列)数据,不能在传统的前馈神经网络(FNN)很好应用的问题。时间序列数据是指在不同时间点上收集到的数据,这类数据反映了某一事物、现象等随时间的变化状态或程度,即输入内容的上下文关联…

工业现场实测,焦化厂导烟车与装煤车风机实现无人作业

一、项目背景 作为我国重要的能源行业之一,焦化行业在国民经济中扮演着重要角色,焦化工艺是高温、高压、有毒物质等因素共同作用下进行的,因此存在着安全隐患,并伴有环境污染,改善焦化工艺的安全和环保问题是当前亟待…

优选算法之前缀和(下)

目录 一、和为 k 的子数组 1.题目链接:560. 和为 K 的子数组 2.题目描述: 3.解法(前缀和 哈希表) 🌻算法思路: 🌻算法代码: 二、和可被 k 整除的子数组 1.题目链接&#xff…

MySQL中多表查询之外连接

首先先来介绍一下我做的两个表,然后再用他们两个举例说明。 -- 创建教师表 create table teachers( id_t int primary key auto_increment, -- 老师编号 name_t varchar(5) -- 姓名 ); -- 创建学生表 create table students( id_s int primary key auto_increment,…

Android APK混淆处理方案分析

这里写目录标题 一、前言1.1 相关工具二、Apk 分析2.1 apk 解压文件2.2 apk 签名信息2.3 apk AndroidManifest.xml2.4 apk code三、Apk 处理3.1 添加垃圾文件3.2 AndroidManifest.xml 处理3.3 dex 混淆处理3.4 zipalign对齐3.5 apk 重新签名3.6 apk 安装测试四、总结一、前言 提…

使用Astro+Vercel+Cloudflare一天时间开发部署上线一个知识博客网站,简直简简单单

大家好,这里是程序猿代码之路。在当今数字化时代,拥有一个个人博客网站对于分享知识、展示个人品牌变得越来越重要。然而,许多非技术背景的用户对于搭建和维护一个网站可能会感到望而却步。幸运的是,随着低代码和无代码平台的兴起…

Spring高手之路21——深入剖析Spring AOP代理对象的创建

文章目录 创建代理对象核心动作的三个步骤1. 判断 Bean 是否需要增强(源码分析时序图说明)2. 匹配增强器 Advisors(源码分析时序图说明)3. 创建代理对象(源码分析时序图说明) 创建代理对象核心动作的三个步…

C++模版基础知识与STL基本介绍

目录 一. 泛型编程 二. 函数模板 1. 概念 2. 函数模版格式 3. 函数模版的原理 4. 模版函数的实例化 (1). 隐式实例化 (2.) 显式实例化 5. 模版参数的匹配原则 三. 类模板 1. 类模板的定义格式 2. 类模板的实例化 四. STL的介绍 1. 什么是STL? 2. STL的版…

netty入门-7 ByteBuf

文章目录 前言ByteBuf结构池化与非池化创建(直接内存/堆内存)写入和读取释放零拷贝,slice,duplicate, copy,Composite 结语 前言 ByteBuf这部分视频讲的更为详细。 主要参考视频。 ByteBuf 结构 首先这…

C# Task.WaitAll 的用法

目录 简介 1.WaitAll(Task[], Int32, CancellationToken) 2.WaitAll(Task[]) 3.WaitAll(Task[], Int32) 4.WaitAll(Task[], CancellationToken) 5.WaitAll(Task[], TimeSpan) 结束 简介 Task.WaitAll 是 C# 中用于并行编程的一个的方法,它属于 System.Threa…

开始尝试从0写一个项目--后端(三)

器材管理 和员工管理基本一致,就不赘述,展示代码为主 新增器材 表设计: 字段名 数据类型 说明 备注 id bigint 主键 自增 name varchar(32) 器材名字 img varchar(255) 图片 number BIGINT 器材数量 comment VARC…

Elasticsearch 使用误区之三——分片设置不合理

Elasticsearch 是一个强大的搜索和分析引擎,它通过将数据分散到多个节点的分片中来进行分布式处理。 本文将探讨分片大小和策略的概念,以优化 Elasticsearch 的性能并防止过度分片或分片过大等问题。 先看个分片设置不合理的真实企业案例: 10…

陶晶驰串口屏使用记录与教程

首先把串口屏想象成和正点原子usmart调试程序一样的程序,串口屏主芯片有些是GD32 STM32都是主流单片机,里面下载了一些固件形成了现在的操作系统 其实我更喜欢把他们(usmart,串口屏主程序,micropython,at指…

uniapp vue3 使用画布分享或者收藏功能

使用HBuilder X 开发小程序,大多数的画布插件很多都是vue2的写法,vue3的很少 我自己也试了很多个插件,但是有一些还是有问题,不好用 海报画板 - DCloud 插件市场 先将插件导入项目中 自己项目亲自用过,功能基本是完善…

GraphRAG:基于实体的本地搜索方法:知识图谱与非结构化数据的融合

GraphRAG:基于实体的本地搜索方法:知识图谱与非结构化数据的融合 在自然语言处理和信息检索领域,如何有效地结合结构化知识和非结构化文本数据一直是一个重要的研究方向。本文介绍一种基于实体的本地搜索方法,该方法巧妙地融合了知识图谱中的结构化数据和输入文档中…

优化冗余代码:提升前端项目开发效率的实用方法

目录 前言代码复用与组件化模块化开发与代码分割工具辅助与自动化结束语 前言 在前端开发中,我们常常会遇到代码冗余的问题,这不仅增加了代码量,还影响了项目的可维护性和开发效率。还有就是有时候会接到紧急业务需求,要求立马完…

打造一篇完美的【数学建模竞赛论文】:从准备到撰写的全面指南

目录 一、赛前准备 1.1 报名与纪律要求 1.2 MD5码上传 1.3 竞赛准备 1.4 时间分配 二、论文格式规范 2.1 摘要 2.2 参考文献 2.3 排版要求 三、建模过程与方法 3.1 问题分析与模型假设 3.2 模型构建与求解 3.3 结果分析与检验 四、论文撰写技巧 4.1 论文结构 4…