SQL进阶理论篇(十):数据库中的锁

文章目录

  • 简介
  • 按照锁的粒度进行划分
  • 从数据库管理的角度进行划分
  • 从程序员的角度进行划分
  • 为什么共享锁会发生死锁?
  • 参考文献

简介

索引和锁,是数据库中的两个核心知识点。

索引的相关知识点,在之前的几章里我们已经介绍的差不多了。接下来我们会重点讲解一下锁的相关知识。

事务的隔离级别,在底层就是通过锁来实现的。而加锁的目的,就是为了保证数据的一致性。

本节我们将重点描述以下几个问题:

  • 锁有哪些划分方式?
  • 为什么共享锁会发生死锁?
  • 乐观锁和悲观锁的思想是什么?乐观锁有哪两种实现方式?
  • 多个事务并发,发生死锁时该如何解决?如何降低死锁发生的概率?

按照锁的粒度进行划分

锁是用来对数据进行锁定的。我们可以根据被锁定对象的粒度大小来对锁进行划分,即:行锁、页锁和表锁

行锁,按照行粒度对数据进行锁定。由于锁定力度小,所以发生锁冲突的概率低,理论上可以实现的并发度很高。但是按行加锁,对资源的消耗太大了,而且加锁也比较慢,容易出现死锁现象。

页锁,就是在页的粒度上对数据进行锁定。因为一个页上可以有很多数据行,所以在使用页锁的时候,很容易会出现数据浪费的情况(即使只是想锁小部分数据,也得锁上一整页),但是这种浪费有限,顶多就是浪费个几页。页锁的开销介于行锁和表锁之间,会出现死锁,并发度一般。

表锁,就是对数据表进行锁定。其锁定粒度很大,出现锁冲突的概率也很高,对并发的影响较大。好处是加锁的开销小,加锁很快。

以上三类锁是数据库中相对常见的三种锁,除此之外其实还有区锁和数据库锁,分别针对区和数据库的粒度。

不同的数据库或者不同的引擎支持的锁粒度并不相通。以MySQL为例,InnoDB支持行锁和表锁,但MyISAM只支持表锁,BDB引擎则支持页锁和表锁。Oracle支持行锁和表锁,SQLServer同时支持行锁、页锁和表锁。教程里整理的图如下:

在这里插入图片描述

需要注意,在实际使用中,每个层级的锁数量是有限的,因为锁会占用内存空间,所以锁空间的大小是有限的。

当某个层级的锁数量超过了这个层级的阈值时,就会进行 锁升级。所谓的锁升级,就是将多个细粒度的锁升级成一个更大粒度的锁。比如说在InnoDB中,将多个行锁换成一个表锁,从而减少锁空间的内存占用,当然,代价是并行度降低了。

从数据库管理的角度进行划分

从数据库管理的角度来划分的话,就是我们经常会见到的两种锁:共享锁和排它锁

共享锁,也叫做读锁或者S锁。共享锁锁定的数据可以被其他事务读取,但是不能修改。

在进行select的时候,就会把对象进行共享锁锁定,待到数据读取完毕后,才释放共享锁。这样子可以保证数据在读取时不会被修改。

我们也可以手动给某个对象加锁。

比如说给一个表加共享锁,可以使用:

LOCK TABLE product_comment READ;

这时候这张表就是只读模式了,如果此时再执行update语句,会提示:

ERROR 1099 (HY000): Table 'product_comment' was locked with a READ lock and can't be updated

解锁的话,可以使用:

UNLOCK TABLE product_comment;

如果是想给某一行加上共享锁,则可以写成这样:

SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE user_id = 912178 LOCK IN SHARE MODE

排它锁,也叫做独占锁、写锁或者X锁。其锁定的数据只允许进行锁定的事务使用,其他事务无法对已锁定的数据进行读取或者修改。

比如给一个表添加排它锁,可以这么写:

lock table product_comment write;

此时,其他事务就不能在这张表上读或者更新了,有兴趣可以开两个MySQL客户端试一下。

释放锁的话,则是执行:

unlock table;

同样的,想在某个数据行上添加排它锁,可以写成这样:

SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE user_id = 912178 FOR UPDATE;

当我们在对数据进行更新的时候,就是insert、delete或者update的时候,数据库就会自动使用排它锁,避免其他事务对该数据资源进行操作。

当我们想要获取某个数据表的排它锁的时候,需要先看下这张表里有没有已经上了排它锁。如果这个数据表中的某个数据行被上了行锁,我们就无法获取排它锁。这时候就引出来意向锁。

意向锁(Intent Lock),就是给更大一级的空间示意里面是否已经上过锁。在实际场景中,如果我们给某个数据行加上了排它锁,那么数据库会自动给更大一级的空间(比如说数据页或者数据表)加上一个意向锁,用来告知其它事务,这个数据页或数据表里已经有人上过排它锁了。其他事务再不需要一行一行去查看到底这个表里有没有锁。

于是,如果事务想要获取某些记录的共享锁,那么就会给整个表添加 意向共享锁 。同理,如果事务想要获取某些记录的排它锁,就会给整个表添加 意向排它锁。意向锁会告诉其他事务,有人已经锁定了部分记录,你无权进行某些全表扫描的操作了。

从程序员的角度进行划分

从程序员的角度来看待锁的话,可以把锁分为乐观锁和悲观锁。这两种锁实际上是两种不同的看待数据并发的思维方式,它们并不是锁。这个简单了解下就行。

乐观锁(Optimistic Locking),认为对同一数据的并发操作是属于小概率事件,可以忽略,因此不用每次都对数据进行加锁,也就是不采用数据库自身的锁机制,而是通过程序,采用版本号机制或者时间戳机制来实现。

什么是版本号机制呢?

就是在表里增加一个version字段,事务里第一次读的时候会先获取version字段的取值,接下来如果需要对数据做update,则会执行UPDATE ... SET version=version+1 WHERE version=刚刚的version取值。如果没有其他事务对这条数据做过修改,那么本次update就成功了,反之,本次update失败(因为version已经被其他事务修改过了,你保存的这个version值已经找不到数据了)。

什么是时间戳机制呢?

跟版本号一样,只不过添加的是一个时间戳字段,更新的时候判断时间戳字段跟之前读到的是不是一样,一样就成功更新,否则就失败。

所以乐观锁实际上就是程序员自己控制数据并发操作的权限,自行判断数据是否被并发修改过。

悲观锁(Pessimistic Locking),也是一种思想,对数据会被并发修改持保守态度,指代的是通过数据库本身的锁机制来保证数据一致性

与行锁、共享锁等的关系如图:

在这里插入图片描述

乐观锁和悲观锁的适用场景:

  • 乐观锁适合读操作多的场景,相对的写操作很少。其优点是不存在死锁问题。但是要完全排掉相关的数据库操作。
  • 悲观锁则适合写操作多的场景。因为写操作的排它性,可以有效防止读写和写写的冲突。

为什么共享锁会发生死锁?

简单的说一个场景,就是事务A和B都对指定数据行进行了select查询,从而分别获取了对指定数据行的读锁,接着不提交事务,都各自对这条数据进行update。

对事务A来讲,其update会因为事务B持有读锁而失败,然后它会提示超时,重新执行事务。

而对事务B来讲,其update则会因为事务B持有读锁而失败,同样提示超时,重新执行事务。两边这就陷进死循环了,死锁发生。

当死锁发生的时候,只能让其它事务进行回滚,指定一个事务获取锁完成事务,然后将锁释放掉,再换下一个事务。

可以采取什么方式避免死锁的发生呢?

  • 如果事务涉及多个表,各部分操作比较复杂,那么可以考虑一次性锁定所有资源,而不是逐步获取。比如说MyISAM引擎就是这样,总是一次性获取全部的锁,要么全部满足可以执行,要不就全部等待;
  • 如果需要更新表中大部分数据,可以考虑使用表锁来代替行锁,即使用锁升级;

避免死锁,其实就是破坏产生死锁的四个必要条件:

  • 互斥条件:同一时刻,资源只能被一个对象使用;
  • 占有且等待条件:对象占有资源,同时在等待被其他对象占有的资源;
  • 不可剥夺条件:已经分配的锁不能强制剥离,只能有持有该锁的事务主动释放;
  • 循环等待条件:对象A占有对象B需要的资源,对象B占有对象A需要的资源。

以上条件必须同时具备,才能产生死锁。这个了解下就行。

参考文献

  1. 30丨锁:悲观锁和乐观锁是什么?

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

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

相关文章

[pasecactf_2019]flask_ssti proc ssti config

其实这个很简单 Linux的/proc/self/学习-CSDN博客 首先ssti 直接fenjing一把锁了 这里被加密后 存储在 config中了 然后我们去config中查看即可 {{config}} 可以获取到flag的值 -M7\x10wd94\x02!-\x0eL\x0c;\x07(DKO\r\x17!2R4\x02\rO\x0bsT#-\x1cZ\x1dG然后就可以写代码解…

MNIST内置手写数字数据集的实现

torchvision库 torchivision库是PyTorch中用来处理图像和视频的一个辅助库,接下来我们就会使用torchvision库加载内置的数据集进行分类模型的演示 为了统一数据加载和处理代码,PyTorch提供了两个类用于处理数据加载,他们分别是torch.utils.…

机器视觉技术与应用实战(开运算、闭运算、细化)

开运算和闭运算的基础是膨胀和腐蚀,可以在看本文章前先阅读这篇文章机器视觉技术与应用实战(Chapter Two-04)-CSDN博客 开运算:先腐蚀后膨胀。开运算可以使图像的轮廓变得光滑,具有断开狭窄的间断和消除细小突出物的作…

饥荒Mod 开发(十五):小地图显示物品

饥荒Mod 开发(十四):制作屏幕弹窗 本篇源码 饥荒中按下Tab键可以显示地图,刚开始进入游戏的时候地图是未探索状态,所以我们并不知道地图上面的物品分布情况。并且地图上只会显示很少一部分的物品,比如树枝,草&#xf…

C++二维数组(4)

蛇形遍历 题目描述:用数字1,2,3,4,...,n*n这n2个数蛇形填充规模为n*n的方阵。 蛇形填充方法为: 对于每一条左下-右上的斜线,从左上到右下依次编号1,2,...,2n-1;按编号从小到大的顺序,将数字从小到大填入各 条斜线&…

链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)

目录 一、双向链表的概念 二、 双向链表的优缺点分析​与对比 2.1双向链表特点: 2.2双链表的优劣: 2.3循环链表的优劣 2.4 顺序表和双向链表的优缺点分析​ 三、带头双向循环链表增删改查实现 3.1SList.c 3.2创建一个新节点、头节点 3.3头插 3.…

C# WPF上位机开发(知识产权ip保护)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 上位机软件如果是和硬件模块搭配开发,这个时候大部分上位机基本上都是白送的,不会收取相关的费用。但是,如果上…

chrome升级后,调试vue在控制台输出总是显示cjs.js

当前chrome版本120.0.6099.72 在vue中使用console.log输出时,总是显示cjs.js多少多少行,不能显示源文件名及行数 【解决方案】 打开控制台的设置 左侧找到“Ignore List”,取消勾选"enable Lgnore Listing",并重启chr…

【Jmeter】Jmeter基础6-Jmeter元件介绍之前置处理器

前置处理器主要用于处理请求前的准备工作,如:参数、环境变量的设置等。 2.6.1、JSR223预处理程序 作用:请求前的准备工作。 参数说明: 语言:开发脚本所使用的语言,可通过下拉列表选择。参数:传…

Linux实操——安装Mysql

安装Mysql 一、检查是否已经安装了mariadb数据库,并卸载二、下载mysql包,并通过ftp上传到服务器三、解压安装包四、创建数据存储文件夹五、创建执行mysqld命令的用户,并初始化mysql六、启用传输安全七、启动mysql,验证是否安装成功 总结 博主…

【Hive】——DDL(DATABASE)

1 概述 2 创建数据库 create database if not exists test_database comment "this is my first db" with dbproperties (createdByAllen);3 描述数据库信息 describe 可以简写为desc extended 可以展示更多信息 describe database test_database; describe databa…

技术分享 | 接口测试价值与体系

如果把测试简单分为两类,那么就是客户端测试和服务端测试。移动端的测试包括 UI 测试,兼容性测试等,服务端测试包括接口测试。接口测试检查数据的交换、传递和控制管理过程。它绕过了客户端,直接对服务端进行测试。 接口测试的价值…

链表之带头双向循环链表(C语言版)

我们之前已经介绍过链表的知识了,这里我们直接开始实现带头双向循环链表 数据结构之单链表(不带头单向非循环链表)-CSDN博客 第一步:定义结构体 //定义结构体 typedef int SLTDateType; typedef struct Listnode {SLTDateType d…

字符设备驱动框架的编写

一. 简介 我们在学习裸机或者 STM32 的时候关于驱动的开发就是初始化相应的外设寄存器,在 Linux 驱动开发中,肯定也是要初始化相应的外设寄存器。 只是在 Linux 驱动开发中, 我们需要按照其规定的框架来编写驱动,所以说学 …

【HTML5、CSS3】新增特性总结!

文章目录 23 HTML5 新增特性23.1 语义化标签23.2 多媒体标签23.2.1 视频<video>标签23.2.2 音频<audio>标签 23.3 input属性值23.4 表单属性 24 CSS3 新增特性24.1 属性选择器24.2 结构伪类选择器24.2.1 选择第n个元素24.2.2 常用的6个结构伪类选择器 24.3 伪元素选…

如何用Python向图像中加入噪声

我们在做机器视觉项目的过程中&#xff0c;有的时候需要向图像中加入噪声。Pytorch本身不支持类似的功能&#xff0c;如果自己写的话&#xff0c;不但麻烦&#xff0c;而且容易出错。好在skimage支持这个功能。代码如下&#xff1a; import skimage import matplotlib.pyplot …

抚琴成一快-布鲁斯

布鲁斯 0.理论1.音阶1.大调布鲁斯音阶2.小调布鲁斯音阶 1.基础1.shuffle节奏制音2.十二小节3.和弦4.小调五声音阶 2.演奏手法1.Lamp and Lamp1.基础和声进行2.进阶和声进行1.quick change2. call and respond:3.回旋句 2.Box1.基础和声进行2.进阶和声进行 3.Boogie1.基础节奏2.…

【教学类-06-19】20231217 (按“列”正序题)X-Y之间“加法题+题”(1页最多0-13。填满115空格)

作品展示&#xff1a;按列排序&#xff0c;从小到大正序&#xff08;没有大量空格&#xff09; 1.会有空格做分割线&#xff0c;上面部分是所有的小到大正序加法&#xff0c;下面的部分就是正序题目的不重复随机抽取题目&#xff08;乱序题&#xff09; 2、包含分割空格&…

实验记录:深度学习模型收敛速度慢有哪些原因

深度学习模型收敛速度慢有哪些原因&#xff1f; 学习率设置不当&#xff1a; 学习率是算法中一个重要的超参数&#xff0c;它控制模型参数在每次迭代中的更新幅度。如果学习率过大&#xff0c;可能会导致模型在训练过程中的振荡&#xff0c;进而影响到收敛速度&#xff1b;如果…

【Windows】windows11右键默认显示更多选项的办法

Windows11系统的右键菜单显示&#xff0c;需要多点一次“显示更多选项”才能看到所有菜单内容&#xff0c;按下面步骤简单设置一下就能恢复成Windows经典的右键菜单显示。 1. 2.输入命令【reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a…