InnoDB存储引擎中的锁(整理)

目录

什么是锁

InnoDB存储引擎中的锁

锁的类型

锁的兼容性

一致性非锁定读

一致性锁定读

锁的算法

行锁的三种算法

Phantom Problem(幻像问题)

锁问题

脏读

不可重复读

丢失更新

死锁


什么是锁

在数据库中锁是为了解决资源争抢的问题,锁是数据库系统区别于文件系统的一个关键特性。锁机制用于管理对共享资源的并发访问。

数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性。

InnoDB存储引擎区别于MyISAM的两个重要特征就是:InnoDB存储引擎支持事务和行级别的锁,MyISAM只支持表级别的锁。

InnoDB存储引擎中的锁

锁的类型

InnoDB存储引擎实现了如下两种标准的行级锁:

  • 共享锁(S Lock),允许事务读一行数据。
  • 排他锁(X Lock),允许事务删除或更新一行数据。
锁的兼容性

如果一个事务T1已经获得了行r的共享锁,那么另外的事务T2可以立即获得行r的共享锁,因为读取并没有改变行r的数据,称这种情况为锁兼容(Lock Compatible)。

但若有其他的事务T3想获得行r的排他锁,则气必须等待事务T1、T2释放行r上的共享锁——这中情况称为锁不兼容。如表所示:

-X(排他锁)S(共享锁)
X(排他锁)不兼容不兼容
S(共享锁)不兼容兼容

 从表中可以发现X锁与任何的锁都不兼容,而S锁仅和S锁兼容。需要特别注意的是,S和X锁都是行锁,兼容是指对同一记录(row)锁的兼容性情况

此外,InnoDB存储引擎支持多粒度(granular)锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,称之为意向锁(Intention Lock)。意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度(fine granularty)上进行加锁。

如上图,数据库从上到下可以分为数据库、表、页、记录四个层次,行记录是最细粒度的锁,我们在获取行锁的时候,需要从上到下各个级别分别进行锁定,最后才能获取到行锁。比如,你要获取行记录x的锁,需要先在数据库、表、页上加意向锁IX,其中任何一方需要等待锁,会造成行锁的等待。

举例:在对记录r加X锁之前,已经有事务对表1进行了S表锁,那么表1已存在S锁,之后事务需要对记录r在表1上加上IX,由于不兼容,所以该事务需要等待表锁操作的完成。

InnoDB存储引擎支持的意向锁即为表级别的锁。支持两种意向锁:

  • 意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁
  • 意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁

由于InnoDB存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫以外的任何请求。故表级意向锁与行级锁的兼容性如表所示:

-IS(意向共享锁)IX(意向排他锁)S(共享锁)X(排他锁)
IS(意向共享锁)兼容兼容兼容不兼容
IX(意向排他锁)兼容兼容不兼容不兼容
S(共享锁)兼容不兼容兼容不兼容
X(排他锁)不兼容不兼容不兼容不兼容
一致性非锁定读

一致性的非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。

如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放。

相反地,InnoDB存储引擎会去读取行的一个快照数据。

快照数据是指该行的之前版本的数据,该实现是通过undo段来完成。而undo用来在事务中回滚数据,因此快照数据本身是没有额外的开销。此外,读取快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改操作。

快照数据其实就是当前行数据之前的历史版本,每行记录可能有多个版本。如上图记录就有多个历史的快照版本。(Snapshot Data、Snapshot Data 2)
这就是大名鼎鼎的MVCC。

多版本并发控制(Multi Version Concurrency Control,MVCC)是指一个行记录有多个快照版本,由多个快照版本引发的并发控制,叫做多版本并发控制。

那这么多历史的快速版本,访问的时候该用哪一个呢?

  • 在READ COMMITTED事务隔离级别下,非一致性读总是读取被锁定行的最新一份快照数据。
  • 在REPEATABLE READ事务隔离级别下,非一致性读总是读取事务开始时的行数据版本。

由此可见,不同的事务隔离级别在MVCC的处理上还不一样。

一致性锁定读

在默认配置下,即事务的隔离级别为REPEATABLE READ模式下,InnoDB存储引擎的SELECT操作使用一致性非锁定读。

但是在某些情况下,用户需要显式地对数据库读取操作进行加锁以保证数据逻辑的一致性。

InnoDB存储引擎对于SELECT语句支持两种一致性的锁定读(locking read)操作:

  • SELECT…FOR UPDATE 对读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁。
  • SELECT…LOCK IN SHARE MODE对读取的行记录加一个S锁,其他事务可以向被锁定的行加S锁,但是如果加X锁,则会被阻塞。

对于一致性非锁定读,即使读取的行已被执行了SELECT…FOR UPDATE,也是可以进行读取的,此外,SELECT…FOR UPDATE,SELECT…LOCK IN SHARE MODE必须在一个事务中,当事务提交了,锁也就释放了。因此在使用上述两句SELECT锁定语句时,务必加上BEGIN,START TRANSACTION或者SET AUTOCOMMIT=0。

一致性锁定读则需要检查被读取的行上有没有互斥的锁,假如有互斥的锁存在就需要等待锁的释放。

锁的算法

行锁的三种算法
  • Record Lock:单个行记录上的锁。
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。
  • Next-key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身。

Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。

Gap Lock的作用是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生。

用户可以通过以下两种方式来显式地关闭Gap Lock:

  • 将事务的隔离级别设置为READ COMMITTED
  • 将参数innodb_locks_unsafe_for_binlog设置为1

在上述的配置下,除了外键约束和唯一性检查依然需要的Gap Lock,其余情况仅使用RecordLock进行锁定。

但需要牢记的是,上述设置破坏了事务的隔离性,并且对于replication,可能会导致主从数据的不一致。

Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。

当查询的索引含有唯一属性时,InnoDB存储引擎会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。

Phantom Problem(幻像问题)

Phantom Problem是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。

举个例子:

  • 表t由1、2、5这三个值组成
  • 执行select * from t where a>2 for update
  • 上述事务T1并没有提交,那么此时另一个事务T2插入4这个值,并且数据库允许这个操作
  • 那么事务T1再执行上述查询,就得到4、5两笔记录,跟第一次得到的结果不一样,违反了事务的隔离性

 InnoDB存储引擎采用Next-Key Locking的算法避免幻像问题。对于上述的SQL语句select * from t where a > 2 for update,其锁住的不是5这单个值,而是对(2,+∞)这个范围加了X锁。因此任何对于这个范围的插入都是不被允许的,从而避免幻像问题。

InnoDB存储引擎默认的事务隔离级别是REPEATABLE READ,在该隔离级别下,其采用Next-Key Locking的方式来加锁。

而在事务隔离级别READ COMMITTED下,其仅采用RecordLock行锁。

锁问题

脏读

脏读指的就是在不同的事务下,当前事务可以读到另外事务未提交的数据,简单来说就是可以读到脏数据。

脏读发生的条件是需要事务的隔离级别为READ UNCOMMITTED,而目前绝大部分的数据库都至少设置成READ COMMITTED。

InnoDB存储引擎默认的事务隔离级别为READ REPEATABLE,Microsoft SQLServer数据库为READ COMMITTED,Oracle数据库同样也是READ COMMITTED。

不可重复读

不可重复读是指在一个事务内多次读取同一数据集合。在这个事务还没有结束时,另外一个事务也访问该同一数据集合,并做了一些DML操作。因此,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的情况,这种情况称为不可重复读。

不可重复读和脏读的区别是:脏读是读到未提交的数据,而不可重复读读到的却是已经提交的数据,但是其违反了数据库事务一致性的要求。

一般来说,不可重复读的问题是可以接受的,因为其读到的是已经提交的数据,本身并不会带来很大的问题。因此,很多数据库厂商(如Oracle、Microsoft SQL Server)将其数据库事务的默认隔离级别设置为READ COMMITTED,在这种隔离级别下允许不可重复读的现象。

在InnoDB存储引擎中,通过使用Next-Key Lock算法来避免不可重复读的问题。

在MySQL官方文档中将不可重复读的问题定义为Phantom Problem,即幻像问题。在Next-Key Lock算法下,对于索引的扫描,不仅是锁住扫描到的索引,而且还锁住这些索引覆盖的范围(gap)。

因此在这个范围内的插入都是不允许的。这样就避免了另外的事务在这个范围内插入数据导致的不可重复读的问题。因此,InnoDB存储引擎的默认事务隔离级别是READ REPEATABLE,采用Next-Key Lock算法,避免了不可重复读的现象。

丢失更新

丢失更新是另一个锁导致的问题,简单来说其就是一个事务的更新操作会被另一个事务的更新操作所覆盖,从而导致数据的不一致。

  • 事务T1将行记录r更新为v1,但是事务T1并未提交
  • 与此同时,事务T2将行记录r更新为v2,事务T2未提交
  • 事务T1提交
  • 事务T2提交

在当前数据库的任何隔离级别下,都不会导致数据库理论意义上的丢失更新问题。这是因为,即使是READ UNCOMMITTED的事务隔离级别,对于行的DML操作,需要对行或其他粗粒度级别的对象加锁。

死锁

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。

解决死锁问题最简单的一种方法是超时,即当两个事务互相等待时,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚,另一个等待的事务就能继续进行。在InnoDB存储引擎中,参数innodb_lock_wait_timeout用来设置超时的时间。

超时机制虽然简单,但是其仅通过超时后对事务进行回滚的方式来处理,或者说其是根据FIFO的顺序选择回滚对象。但若超时的事务所占权重比较大,如事务操作更新了很多行,占用了较多的undo log,这时采用FIFO的方式,就显得不合适了,因为回滚这个事务的时间相对另一个事务所占用的时间可能会很多。

因此,除了超时机制,当前数据库还都普遍采用wait-for graph(等待图)的方式来进行死锁检测。

较之超时的解决方案,这是一种更为主动的死锁检测方式。InnoDB存储引擎也采用的这种方式。

wait-for graph要求数据库保存以下两种信息:

  • 锁的信息链表
  • 事务等待链表

wait-for graph的死锁检测通常采用深度优先的算法实现,通常来说InnoDB存储引擎选择回滚undo量最小的事务。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux操作系统——多线程

1.线程特性 1.1线程优点 创建一个新线程的代价要比创建一个新进程小得多与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多线程占用的资源要比进程少很多能充分利用多处理器的可并行数量在等待慢速I/O操作结束的同时,程序可执行其他的计…

先进的人工智能促进更好的业务沟通

提升商务沟通效率:了解SaneBox智能电子邮件管理工具 在现代商业环境中,有效的沟通至关重要。 先进的人工智能技术,特别是在电子邮件管理方面,正在改变企业处理沟通的方式,提高效率和个性化。 下面,我们深入…

【1】THIS IS NOT PROLIFIC PL2303. PLEASE CPMTACT YOUR SUPPLIER

0x01 问题描述 连接COM口连接不上,出现THIS IS NOT PROLIFIC PL2303. PLEASE CPMTACT YOUR SUPPLIER.如下图 0x02 问题解决 1、分析后,因为是windows 11 系统,就装一下驱动。右键单击--》属性 2、更新驱动程序--》浏览我的电脑以查找驱动程序…

电脑中了.[nicetomeetyou@onionmail.org].faust勒索病毒,关于数据恢复

文件后缀变成.[nicetomeetyouonionmail.org].faust了怎么办? 当文件后缀变成.[nicetomeetyouonionmail.org].faust时,通常意味着你的计算机系统已经受到了Faust勒索病毒的攻击。这种病毒会利用先进的加密算法对你的文件进行加密,并将文件后缀…

整合qq邮箱发送

目录 &#x1f32e;1.获取qq授权码 &#x1fad3;2.引入依赖 &#x1f9c8;3.配置mail信息 &#x1f95e;4.创建实现类 &#x1f956;5.测试 1.获取qq授权码 点击开启服务&#xff0c;发送信息获取授权码 2.引入依赖 <!--邮件--><dependency><groupId&…

my2sql —— go语言版binlog解析及闪回工具

之前学习过python语言版binlog解析及闪回工具 MySQL闪回工具简介 及 binlog2sql工具用法 最近听同事介绍有了新的go语言版的my2sql。优点是不需要安装一大堆依赖包&#xff0c;直接可以安装使用&#xff0c;并且解析更高效&#xff0c;试用一下。 一、 下载安装 1. 软件下载 …

学习笔记-华为IPD转型2020:3,IPD的实施

3. IPD的实施 1999 年开始的 IPD 转型是计划中的多个转型项目中的第一个&#xff08;Liu&#xff0c;2015&#xff09;。华为为此次转型成立了一个专门的团队&#xff0c;从大约20人开始&#xff0c;他们是华为第一产业的高层领导。董事会主席孙雅芳是这个团队的负责人。该团…

minio 文件分片上传和下载

文件下载 文件分片下载&#xff1a; 计算文件开始字节位置&#xff0c;计算文件结束字节位置添加头部信息: Range:bytes0-2000表示开始字节位置&#xff0c;200表示结束字节位置 文件上传 生成

1058:求一元二次方程

【题目描述】 利用公式 求一元二次方程axbxc0的根&#xff0c;其中a不等于0。结果要求精确到小数点后5位。 【输入】 输入一行&#xff0c;包含三个浮点数a,b,c&#xff08;它们之间以一个空格分开&#xff09;&#xff0c;分别表示方程axbxc0的系数。 【输出】 输出一行&…

三款.NET代码混淆工具比较分析:ConfuserEx、Obfuscar和Ipa Guard

随着.NET应用程序的广泛应用&#xff0c;保护知识产权和防止逆向工程的需求逐渐增长。本文将详细介绍三款知名的.NET代码混淆工具&#xff1a;ConfuserEx、Obfuscar和Ipa Guard&#xff0c;帮助读者全面了解其功能特点和应用场景。 一、ConfuserEx ConfuserEx是一个.NET代码混…

SpringCloud-Nacos配置管理

在nacos中添加配置文件 如何在nacos中管理配置呢&#xff1f; 然后在弹出的表单中&#xff0c;填写配置信息&#xff1a;如&#xff1a;userservice-dev.yaml 注意&#xff1a;项目的核心配置&#xff0c;需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置…

【解决】Github Pages搭建的网页访问加载缓慢

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 文章目录 一、CDN技术简介二、基于Cloudflare平台使用CDN服务&#xff08;一&#xff09;添加网站&#xff08;二&#xff09…

基于springboot小区物业管理系统

摘 要 在网络信息的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;小区物业只能以客户为导向&#xff0c;以产品的持续创新作为小区物业最重要的竞争手段。 采取MyS…

蓝桥杯之简单数论冲刺

文章目录 取模快速幂 取模 这道题目有两个注意点&#xff1a; 1.当你的取模之后刚好等于0的话&#xff0c;后面就不用进行后面的计算 2.if sum detail[i] > q: 这个语句的等号也很重要 import os import sys# 请在此输入您的代码a,b,n map(int,input().split())week a*5 …

[linux]--关于进程概念(上)

目录 冯诺依曼体系结构 操作系统 概念 设计os的目的 定位 如何理解管理 总结 系统调用和库函数概念 进程 描述进程-pcb 组织进程 查看进程 通过系统调用获取进程标示符 通过系统调用创建进程-fork初识 进程状态 阻塞和挂起 Z(zombie)-僵尸进程 冯诺依曼体系结…

spring整合Sentinel

安装sentinel&#xff1a; 执行命令; java -jar sentinel-dashboard-1.8.6.jar 注:sentinel的默认端口为8080&#xff0c;容易出现tomcat的冲突。 当端口冲突&#xff0c;可以使用该指令修改sentinel的端口 默认账号和密码都为sentinel Springcloud整合sentinel&#xff1a;…

IDA反汇编工具详解之菜单栏和基本操作

文章目录 IDA 菜单栏FileEditJumpSearchViewDebuggerOptionsWindows 反汇编操作名称和命名IDA 中的注释基本代码转换修改exe文件并保存 IDA 菜单栏 File File菜单负责项目工程的管理&#xff0c;操作包括:打开项目、关闭项目、保存项目 Edit Edit菜单负责编辑和管理该项目中的…

matlab 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面

1、内容简介 略 65-可以交流、咨询、答疑 2、内容说明 matlab 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面 李雅普洛夫指数谱、相图、分岔图、庞加莱界面 3、仿真分析 略 4、参考论文 略

队列的算法

数组队列 数组的子集 主要方法addLast( )和removeFirst( ) public interface IQueueDesc<E>{void enqueue(E e);E dequeue();E getFront();int getSize();boolean isEmpty(); }public class QueueMyList<E> implements IQueueDesc<E{MyArray<E> a…

深度学习500问——Chapter03:深度学习基础(4)

文章目录 3.7 预训练与微调&#xff08;fine tuning&#xff09; 3.7.1 为什么无监督预训练可以帮助深度学习 3.7.2 什么是模型微调 fine tuning 3.7.3 微调时候网络参数是否更新 3.7.4 fine-tuning模型的三种状态 3.8 权重偏差和初始化 3.8.1 全都初始化为0 3.8.2 全都初始化为…