关于InnoDB的读写锁类型以及加锁方式

article/2025/8/19 1:36:01

(本文为了方便,英文关键词都都采用小写方式,相关知识点会简单介绍,争取做到可以独立阅读)

文章开始我会先介绍本文需要的知识点如下:

 

  • innodb的主键索引(一级索引)和二级索引(辅助索引)的知识
  • innodb的隔离级别isolation level
  • MVCC(Multi-Version Concurrent Control)多版本并发控制
  • 数据的脏读、幻读(如果有时间会详细讲一下脏读如果没时间,网上讲这个地方的也很多)
  • 简单的sql知识(能读懂sql语句)
我们先看一个mysql表和几条语句,方便后面使用
表名称: my_table  
搜索引擎:innodb
表结构:
1. select * from my_table where id = 1;
2. select * from my_table where id = 1 lock in share mode;
3. select * from my_table where id = 1 for update;
4. update my_table set address = 'tianjin' where id = 1;
先说 隔离级别,mysql 隔离级别分为四种:
未提交读( read uncommitted )、提交读(read committed)、重复读(repeatable read)、序列化(serializable
其中mysql默认的隔离级别重复读(repeatable read),以下简称为rr,本文也只介绍这种模式

问题1:读有几种模式、加锁有几种方式

读的模式分为两种:

  • 快照读(snapshot read)
  • 当前读(current read)

在聊读模式之前,我们需要先来了解一下MVCC:

MVCC是为了实现数据库的并发控制而设计的一种协议。与其相对的是LBCC 即基于锁的并发控制(Lock-Based Concurrent Control)。要实现数据库的并发访问控制,最简单的做法就是加锁访问,即读的时候不能写( 这个读为当前读,后面介绍。允许多个线程同时对想读的内容加锁,即共享锁或叫S锁),写的时候不能读(只能有一个线程对同一内容进行写操作,即排它锁,X锁)。这样的加锁访问,其实并不算是真正的并发,或者说它只能实现并发的读,既读写串行化,这样就大大降低了数据库的读写性能。
LBCC是四种隔离级别中级别最高的Serialize隔离级别。MVCC对比LBCC它的最大好处便是, 读不加锁,读写不冲突,在需要加锁的时候,尽可能的少锁定行(锁策略, 后面有讲 )。

快照读(Snapshot read)和当前读(current read)释义:

  • 快照读,读取的是记录的可见版本(可能是历史版本,即最新的数据可能正在被当前执行的事务并发修改),不会对返回的记录加锁,如上面的sql语句1

  • 当前读,读取的是记录的最新版本,并且会对返回的记录加锁,保证其他事务不会并发修改这条记录。如上面的sql语句2,3,4。不同的是2加的是s锁,3、4加的是x锁,insert加的也是x锁。

注:MVCC只在RC和RR两个隔离级别下工作,其他两个隔离级别都和MVCC不兼容

加锁的方式:

mysql进行并发控制有两种锁:

  • 共享锁(s锁):也称为读锁,是因为一般是读的过程中加的锁,一个事务加s锁的时候,另一个事务还可以获得s锁,例如语句2
  • 排他锁(x锁):也称为写锁,一个事务加x锁的时候,其他事务拿不到锁,只能等待。例如语句3和语句4
先看一个sql语句
update my_table set name ='zhang' where id = 1;
假设id为主键:此条sql执行的时候会给此行数据加x锁,如下图

 
mysql的innodb默认的隔离模式为 RR模式,既可重复读, Innodb的RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),因此不存在幻读现象。但是 标准的RR只能保证在同一事务中多次读取同样记录的结果是一致的,而无法解决幻读问题。Innodb的幻读解决是依靠MVCC的锁策略实现机制做到的。

主键索引(一级索引)和二级索引

innodb中在主键上存在聚簇索引类型的一级索引,其他的索引均聚簇索引类型的二级索引,这里做一下简单介绍
一级索引:在innodb存储引擎中,主键的存在至关重要,及时你不为表设置主键,存储引擎也会隐式的定义一个主键,只是对用户来说透明。之所以说他重要,是因为聚簇索引的存储是和数据存储在一起的,而聚簇索引的数据就是数据存储的顺序。如果需要查找的数据是连续的,那么按照聚簇索引查找到的数据位置也是连续的,只需要按顺序读取就可以。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页(这里和后面的二级索引有区别,二级索引的叶子节点存储的是主键,需要再进行回聚集索引上(简称回表)查询真实的数据。 。 在一张表上最多只能创建一个聚集索引,因为真实数据的物理顺序只能有一种。
二级索引:表数据存储顺序与索引顺序无关。对于二级索引,其也是聚集索引,但是叶结点不包含真实行数据,只包含索引字段值及主键,其行数量与数据表行数据量一致。

mvcc的锁策略

update my_table set name ='zhang' where id = 1;
看上面的sql语句,或者看之前的几条sql,这个语句执行的时候会给这条记录加x锁,这时候如果其他事务中的语句也在进行锁的操作(既更新、插入或者删除,以及语句2当前读操作加的s锁)就会造成锁争用(innodb出现锁争用的时候处理方式为回滚超时获取不到锁的事务)这种操作当然是惨痛的。
我们在上面说了mvcc的锁策略是尽量减少锁定的行。而且还要解决幻读的问题,所以有了一系列的锁策略(先看总结,后面有实例)。

行锁

对于查询条件为主键和唯一索引的语句:是行级锁,只锁定满足条件的行,record lock。

间隙锁 (gaplock)

对于查询条件为非唯一索引:是范围锁定,锁定范围为索引上按照条件需要扫描的范围

表锁

对于查询条件没有用到索引的语句:直接锁定全表。

 

实例讲解

我们先按照上面四条语句两条并发时的相互影响的情况来
情况1:id为主键
1. select * from my_table where id = 1;
2. select * from my_table where id = 1 lock in share mode;
我们上面说过,语句1为快照读,对其他的读或者写没有影响。所以这两条语句并行时,1读快照,2为语句加s锁。
select * from my_table where id = 1 lock in share mode;
情况2:id为主键
2. select * from my_table where id = 1 lock in share mode;
3. select * from my_table where id = 1 for update;
其中语句2加s锁,3加x锁(在数据被加s锁的时候,其他的给这条想要读取这条记录也需要给这条记录加s锁,这就是为什么s锁是共享锁。此时是不允许再给这条记录加x锁的)两种锁是不能同时存在在一条记录上的。所以两条语句谁先上锁谁先执行,另一个等待。
情况3:id为主键
3. select * from my_table where id = 1 for update;
4. update my_table set address = 'tianjin' where id = 1;
这种情况下两条语句都需要给数据加x锁,所以显然不能并发执行。

下面我们来讨论一下id不为主键的情况

id若不为主键,则不能使用主键索引,而在innodb中有一下几种情况
  • 二级唯一索引
  • 二级不唯一索引
  • 没有索引
由于只要不是快照读则一定会加锁,我们已经了解了锁的形式,则不难明白不论是先加x锁还是s锁哪一种,都一定不能再加另一种锁,所以我们下面只分析加锁的方式
情况4:假设id为二级唯一索引(unique)
4. update my_table set address = 'tianjin' where id = 1;
这里很明显需要加x锁,但是这里的加锁和id为主键(索引为主键索引)的情况加锁不完全一样,会稍微复杂一点
这个时候我们需要对索引知识有一定的了解,上面说过二级索引中的叶子节点存储的除了索引信息还有主键,也就是说我们需要先在二级唯一索引中查找到这条记录的主键,然后通过主键去查找到数据实际的存储位置并给这条数据加锁。注意,这里的加锁应该是加在了索引上和数据本身上(或者说是聚簇索引上也可以,因为两者是存储在一个结构中的)而不只是二级唯一索引上。
情况5:age为二级非唯一索引,id为主键
5. update my_table set address = 'tianjin' where age = 25;
此种情况比前一种情况更特殊,因为情况3和4都只能找到一条记录,只需要对这条记录加锁,则不会发生结果集被修改的情况。但是如果age为二级非唯一索引,我们看到如下表格中有两条记录age=25
如果我们在update的过程中,有一个用户插入了一条age也为25的数据,那么就是发生一种现象,你明明更新了所有的age=25的数据,但是执行完了却有一条数据没有更新的幻觉,这就是幻读(可以自行查找资料,避免本文过长)。这个时候显然只给查找出的数据加锁是解决不了这个问题的。所以就有了gap锁(间隙锁字面上可能更好理解)这里需要画图大家理解一下:
如图这里在age为25的有两个 ,id分别为1和3。我们在修改执行上面语句的时候,如果没有gap锁,则可能发生一种情况:另一个事务执行如下语句
update my_table set age=25 where id=2;
则发生幻读现象。gap锁可以防止在语句或者事务执行过程中有满足条件的记录插入进来造成幻读。所以说在此种情况下,除了给满足条件的二级索引和数据(或聚簇索引)加x锁之外还要给相关的间隙加锁。可以理解为这个加gap锁,不只是锁记录,还要锁边界。是在二级索引的范围内防止新的索引项加入,因为二级索引本身也是有序的。
 
情况6:age上无索引,id为主键
5. update my_table set address = 'tianjin' where age = 25;
这种情况下,所有记录都被加上了X锁,每条记录间的间隙(GAP)也同时被加上了GAP锁,其实就是锁表了。

 


http://chatgpt.dhexx.cn/article/C7TR3jVb.shtml

相关文章

C++线程中的几类锁

C线程中的几类锁 多线程中的锁主要有五类:互斥锁、条件锁、自旋锁、读写锁、递归锁。一般而言,所得功能与性能成反比。而且我们一般不使用递归锁(C提供std::recursive_mutex),这里不做介绍。 互斥锁 互斥锁用于控制多…

Oracle - 锁

锁概念 锁出现在数据共享的环境中,它是一种机制,在访问相同资源时,可以防止事务之间的破坏性交互。例如,在多个会话同时操作某表时,优先操作的会话需要对其锁定。 事务的分离性要求当前事务不能影响其他的事务&#…

用友数据库错误“未能读取并闩锁页(1:3355)(用闩锁类型SH)”修复

客户硬盘无法识别,检测后,硬盘有坏道,由于数据库正在坏道上,所以恢复出来的用友数据库无法附加。 通过无日志附加后,做DBCC检测数据库出现以下错误: “消息8966,级别16,状态1&#x…

Mysql中锁的类型有哪些?

Mysql中锁的类型有哪些? 1. 基于锁的属性分类:共享锁、排他锁2. 基于锁的粒度分类:行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎)、记录锁、间隙锁、临键锁。…

mysql 常见锁的类型(一)

文章目录 一、锁的分类1.1 加锁的目的1.2 锁的类别 二、乐观锁和悲观锁2.1. 乐观锁2.2. 悲观锁: 三、共享锁与排他锁四、表锁五、意向锁六、行级锁七、记录锁(Record Locks)八、间隙锁(Gap Locks)九、临键锁&#xff0…

MySQL-InnoDB常用锁类型解析

Shared(乐观锁) and Exclusive Locks(互斥锁): InnoDB有两种锁类型,Shared(s) and Exclusive(x) Locks(乐观锁和互斥锁)。 Shared&…

MySql InnoDB锁类型

MySql InnoDB锁类型 从类型上来分类,InnoDB存储引擎实现了两种标准的锁 共享锁(S-Lock):允许事务读一行数据 排它锁(X-Lock):允许事务删除或者更新一行数据 如果一个事务获取了S锁,那么其他事务也可以立即获得S锁,…

锁的分类总结

锁的分类是从不同角度去看的。同一个锁也可以同时属于多种类型。 一、乐观锁与悲观锁 1. 互斥同步锁的劣势 阻塞和唤醒会带来性能的劣势 用户态和核心态切换上下文切换检查是否有被阻塞线程需要被唤醒等等 可能出现永久阻塞的问题:持有锁的线程永久阻塞了&#…

锁的介绍和分类(轻量级锁 重量级锁 偏向锁 自旋锁 互斥锁)

目录 公平锁 非公平锁 非公平锁 公平锁 可重入锁 不可重入锁 可重入锁(递归锁) 不可重入锁 轻量级锁 重量级锁 偏向锁 重量级锁 自旋锁(循环上锁) 轻量级锁 轻量级锁的释放 偏向锁 自旋锁和互斥锁 自旋锁 互斥锁 为何要使用自旋锁 自旋…

最全锁种类

你可能听说过很多锁,也看到过很多文章讲解锁,这篇我在这里将对锁的不同分类进行描述锁的设计 互斥锁–共享锁 互斥锁:顾名思义,就是互斥的,意思就是当前同步代码块只能被一个线程访问,sync、reentrantlock、…

锁的类型有哪些

锁的类型有哪些 基于锁的属性分类:共享锁、排他锁。 基于锁的粒度分类:行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎 )、记录锁、间隙锁、临键锁。 基于锁的状态分类:意向共享锁、意向排它锁 共享锁(Share Lock) 共享锁又称读锁&…

Kettle使用教程之Job使用

1、Kettle的Job使用十分简单,这里也只是演示比较简单的操作,创建Job 2、点击转换,然后点击浏览,选择转换对象 3、执行按钮,运行该转换 4、如果需要长期的进行定时转换,可以在Job中的start控件进行配置 转载…

Kettle使用教程之数据同步

Kettle使用教程之数据同步 数据模型原型如下: 1、表输入,针对最新的数据输入的表 2、目标表,需要更新的表 3、两个表都需要进行排序操作 4、合并,根据id进行合并 5、数据同步(包括更新、插入、删除) 6、点击运行,就可…

ETL开发工具KETTLE使用教程

Kettle的建立数据库连接、使用kettle进行简单的全量对比插入更新:kettle会自动对比用户设置的对比字段,若目标表不存在该字段,则新插入该条记录。若存在,则更新。 Kettle简介:Kettle是一款国外开源的ETL工具&#xff0…

ETL工具Kettle使用教程

Kettle使用教程之数据同步 数据同步标识字段 标志字段的值有4种,分别是: “Identical” : 关键字段在新旧数据源中都存在,且域值相同 “changed” : 关键字段在新旧数据源中都存在,但域值不同 “new” : 旧数据源中没有找到该…

Kettle使用教程(一)—— 在MacOS系统中安装 Kettle

Kettle使用教程(一)—— 在MacOS系统中安装 Kettle 一、环境准备二、下载并启动Kettle二、初始化资源库 一、环境准备 Kettle 9.2JDK 1.8 (安装指引)Mysql(安装指引) 二、下载并启动Kettle 首先到官网下…

Kettle使用教程(问题)

关于kettle的介绍此文不做介绍 笔者电脑环境 winoraclejdk1.8kettle7.1 1. 考虑到在在官网下载速度比较慢,在这里可以使用国内的镜像 国内镜像 2. 配置java环境 (1) kettle需要以来java环境,因为没有安装java环境的朋友请移步配置java环境&#xff…

R-P-Faster R-CNN day65 读论文:高分辨率遥感影像综合地理空间目标检测框架

An Efficient and Robust Integrated Geospatial Object Detection Framework for High Spatial Resolution Remote Sensing Imagery 1. Introduction3. Overview of the Proposed R-P-Faster R-CNN Framework3.1. 有效集成区域建议网络与目标检测Faster R-CNN框架3.1.2. RPN与…

多特征融合的高分辨率遥感图像海陆分离——刘思彤

论文阅读笔记 摘要 为解决目前大多数海陆分离方法仅利用单一特征对图像进行处理,从而导致误分割或存在大量孤立区域,造成后续处理工作难度大或无法开展的问题,提出一种联合灰度、梯度和纹理等多特征的海陆分离方法。针对不同的陆地类型选用…

从实现的技术手段细数:高分辨率遥感影像+人工智能的现在和未来

【转自】http://baijiahao.baidu.com/s?id1601901487917871613&wfrspider&forpc 人工智能不可阻挡地向各行业渗透。这一现象,恰巧撞上了“商业遥感卫星发射潮”。这似乎预示了某种潜流。此刻,从事卫星遥感影像解译和大数据提取的专业人士、科研…