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

news2024/12/22 14:39:43

文章目录

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

简介

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

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

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

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

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

按照锁的粒度进行划分

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

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

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

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

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

不同的数据库或者不同的引擎支持的锁粒度并不相通。以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.coloradmin.cn/o/1322821.html

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

相关文章

CEC2013(python):五种算法(HHO、WOA、GWO、DBO、PSO)求解CEC2013(python代码)

一、五种算法简介 1、哈里斯鹰优化算法HHO 2、鲸鱼优化算法WOA 3、灰狼优化算法GWO 4、蜣螂优化算法DBO 5、粒子群优化算法PSO 二、5种算法求解CEC2013 (1)CEC2013简介 参考文献: [1] Liang J J , Qu B Y , Suganthan P N , et al. P…

安卓开发学习---kotlin版---笔记(三)

网络 安卓主页的网络框架&#xff1a;OkHttp 在OkHttp的基础上进行封装的&#xff1a;Retrofit框架&#xff0c;更常使用 OkHttp学习 在使用网络请求的时候&#xff0c;先添加网络访问权限&#xff1a; <uses-permission android:name"android.permission.INTERNET&…

【数据结构】栈的使用|模拟实现|应用|栈与虚拟机栈和栈帧的区别

目录 一、栈(Stack) 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1. 改变元素的序列 2. 将递归转化为循环 3. 括号匹配 4. 逆波兰表达式求值 5. 出栈入栈次序匹配 6. 最小栈 1.5 概念区分 一、栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&…

数据库——水果商店进阶

智能2112杨阳 一、目的与要求&#xff1a; 综合运用SQL语言相关知识如变量、游标、函数、触发器等解决实际问题。 二、内容&#xff1a; 设计并完成以下实验&#xff0c;要求附上源码&#xff08;非截图&#xff09;&#xff0c;测试效果截图 在订单详情表orderitems插入新…

【openGauss/MogDB列存表的delta表测试】

列存储格式是OLAP类数据库系统最常用的数据格式&#xff0c;适合复杂查询、范围统计类查询的在线分析型处理系统。cstore列存储的主体数据文件以CU为I/O单元&#xff0c;只支持追加写操作&#xff0c;因此cstore只有读共享缓冲区。CU间和CU内的可见性由对应的CUDESE表&#xff…

高项-【整合管理】

8.1管理基础 项目整合管理由项目经理负责&#xff0c;责任不能被授权和转移。对整个项目承担最终责任。执行项目整合是担任双重角色&#xff1a; 组织层面&#xff0c;与项目发起人携手合作&#xff0c;了解战略目标&#xff0c;确保项目目标和成果与项目组合、项目集一集业务…

自助借还办证一体机软件需求说明书

1. 简介 1.1 项目概括 本项目主要实现读者自助办证、借书、还书、查询、续借的功能&#xff0c;减轻管理员的工作量&#xff0c;提升读者的借阅体验&#xff0c;提高了图书的借阅量与流通率&#xff0c;是图书馆智能化、无人化建设的重要步骤。 1.2 项目背景 ​ 目前各大图…

【ArkTS】如何修改应用的首页

之前看到一种说法&#xff0c;说是应用首页是 entry > src > main > resources > base > profile > main_pages.json 中src配置中数组第一个路径元素。这种说法是不对的&#xff01;&#xff01;&#xff01; 如果需要修改应用加载时的首页&#xff0c;需要…

软件测试面试题之测试基础,轻松面对面试,一篇足矣

软件测试的流程是什么&#xff1f;&#xff08;测试流程&#xff09; &#xff08;1&#xff09;需求调查&#xff1a;全面了解系统概况、应用领域、软件开发周期、软件开发环境、开发组织、时间安排、功能需求、性能需求、质量需求及测试要求等。根据系统概况进行项目所需的人…

oracle与gbase8s迁移数据类型对照

声明&#xff1a;以下为笔者阅读gbase官方文档和oracle官方文档的理解&#xff0c;如有错误&#xff0c;敬请指正。oracle与gbase8s迁移数据类型对照及举例说明 最终结论&#xff1a;oracle与gbase8s数据类型对应关系关于单精度与双精度的区别关于定点与浮点定义的区别精度的定…

linux之Samba服务器

环境&#xff1a;虚拟机CENTOS 7和 测试机相通 一、Samba服务器_光盘共享&#xff08;匿名访问&#xff09; 1.在虚拟机CENTOS 7安装smb服务&#xff0c;并在防火墙上允许samba流量通过 2. 挂载光盘 3.修改smb.conf配置文件&#xff0c;实现光盘匿名共享 4. 启动smb服务 5.在…

Bezier 曲线 2D

Bezier 曲线于 1962 年由法国雪铁龙汽车公司的工程师 Bezier 所发表&#xff0c;主要应用于汽车的外形设计。虽然 Bezier 曲线早在 1959 年便由法国雷诺汽车公司的 De Casteljau 运用递推算法开发成功&#xff0c;但是 Bezier 却给出了曲线的详细的曲线计算公式。所以&#xff…

游戏、算法竞赛与退役(流水账版)

写在前面 不出意外的话&#xff0c;这东西本该咕到翻年之后再发的&#xff0c;但好像催稿催的有点厉害&#xff0c;于是就找个机会把他写了&#xff08;笑&#xff09; 最初是只想写个算法竞赛退役记的&#xff0c;后面发觉写起来就有点收不住&#xff0c;算法竞赛牵扯到太多…

linux网络管理_配置网络参数

11.2 配置网络参数 ls /etc/sysconfig/network-scripts/ 11.2.1 配置IP 配置网卡参数 # 可考虑先备份 # cp /etc/sysconfig/network-scripts/ifcfg-ens33 . # 复制到当前目录 ​ vim /etc/sysconfig/network-scripts/ifcfg-ens33 ifcfg-ens33文件中的内容 TYPEEthernet PROX…

MATLAB 平面拟合并可视化(34)

MATLAB 平面拟合并可视化(34) 一、效果二、代码一、效果 二、代码 % 生成三维点数据 x = rand(100, 1); y = rand(100, 1

LLaMA系列模型

1.LLama 1.1 简介 Open and Efficient Foundation Language Models (Open但没完全Open的LLaMA) 2023年2月&#xff0c;Meta&#xff08;原Facebook&#xff09;推出了LLaMA大模型&#xff0c;使用了1.4T token进行训练&#xff0c;虽然最大模型只有65B&#xff0c;但在相关评…

Python实战:信用卡客户历史数据挖掘与分析

Python实战&#xff1a;信用卡客户历史数据挖掘与分析 引言数据获取与预处理描述性分析模型建立与评估结果分析Web应用展示&#xff08;可选&#xff09; 引言 信用卡客户历史数据分析是金融领域中的重要课题之一。通过对公开数据集的挖掘&#xff0c;本文将利用Python编程语言…

51单片机LED与无源蜂鸣器模块

IO口的使用1 本文主要对51单片机的LED灯的使用以及蜂鸣器的使用进行介绍&#xff0c;其中包括一些实例分析&#xff1a; 1.实现发光二极管的从左到右的流水点亮 2.左右来回循环的流水灯 3.蜂鸣器以一定频率响 文章目录 IO口的使用1一、LED灯举个栗子一举个栗子二 二、蜂鸣器2.1…

华为OD机试 - 连续出牌数量 - 深度优先搜索dfs算法(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述1、输入2、输出3、说明 四、解题思路1、题目解读2、具体步骤 五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08…