多粒度封锁-封锁粒度、多粒度封锁模式

news2024/11/27 0:46:20

一、引言

1、若采用封锁技术实现并发控制,事务在访问数据库对象前要在数据库对象上加锁,为提高事务的并发程度,商用DBMS会采用一种多粒度封锁方法

2、事务可访问的数据库对象可以是逻辑单元,包括关系、关系中的元组、关系的属性值或属性值集合、关系上的索引项或整个索引、甚至整个数据库等,也可以是物理单元,比如数据所占用的磁盘块 、索引所占用的磁盘块、磁盘块中的物理记录等

3、多粒度封锁技术根据封锁的数据对象的大小不同化分封锁的粒度,将锁加在不同粒度的数据库对象上。在具体DBMS应用时,实现不同的多粒度封锁模式

二、封锁粒度

1、封锁粒度:封锁单元的大小。如果封锁对象单元小,则称为细粒度,否则称为粗粒度

(1)实际应用中,通常细粒度锁是加在元组上的锁,称为元组锁,也称为行级锁

(2)粗粒度锁是加在关系上的锁,称为关系锁,也称为表级锁

对关系加上粗粒度锁后,关系中的所有元组,也被隐式地加上了同样的锁,因此,相对粗粒度锁,使用细粒度锁的事务可以只封锁事务实际访问的数据对象,事务的并发程度会更好

2、比如,对于银行业务系统

如果将账户关系表作为封锁对象,整个关系只能被一个事务加锁,由于业务系统中会有并发的许多事务,对账户表中的不同用户的信息进行更新,这些事务都需要账户关系表上的一个排他锁,那么同一时间只能有一个存款或取款业务能进行,系统中事务的并发程度会很低

 

如果将关系表中的元组作为封锁对象,对不同账户信息进行操作的事务都可以同时对账户信息进行更新

虽然使用细粒度锁使事务的并发程度更好,但由于锁的信息要占用系统的内存空间,并需要DBMS的并发控制机制花费系统时间来管理

3、因此封锁粒度的选择需同时考虑管理锁的开销事务并发度两个因素,以获得最佳的系统性能

4、为此,有的DBMS实现了多粒度封锁功能,来更好地满足应用需求和提高系统性能

(1)比如,对于需要处理大量元组的事务,可以选择关系为封锁粒度

(2)而对于只处理少量元组的用户事务,选择以元组为封锁粒度更合适

(3)也可允许事务根据操作需要来选择封锁粒度

三、多粒度封锁模式

1、不同的DBMS实现的多粒度封锁模式不同,比如SQL Server提供了如下几种锁

(1)NOLOCK锁:用于SELECT语句,读数据前不用申请数据对象上的锁

(2)TABLOCK锁:在关系表上加共享锁,在读完数据后立即释放锁

(3)HOLDLOCK保持锁:用于TABLOCK后,可将共享锁保留到事务完成,而不是读完数据立即释放锁

(4)UPDLOCK锁:在操作语句中满足条件的指定元组上加更新锁,允许对这些元组进行更新操作,其他事务可以对同一关系表中的其他元组也加更新锁,但不允许对表加共享锁和共享锁

(5)TABLOCKX锁:在关系表上加排他锁

2、该封锁模式对应的封锁策略,可用这个锁相容矩阵来描述

3、SQL Server提供在SELECT、INSERT、UPDATE和DELETE等语句中添加WITH子句来显示地进行封锁操作

SELECT SNO,GRADE
FROM SC WITH(TABLOCK)
WHERE SNO='202218014030'

4、下面我们基于创建的学生选课数据库,在SQL Server上通过两个并发事务的执行,来理解多粒度封锁技术的应用。

(1)我们通过在SQL Server的对象资源管理器上打开两个查询窗口来执行两个并发事务,请在事务的并发执行过程中并发调度中每一步的操作结果,分析操作的封锁情况以及多粒度封锁对事务的并发性和数据一致性的影响

(2)在查询窗口1开始执行事务T1,首先对关系表SC表中SNO='202218014030' 的元组进行查询,使用TABLOCK锁得到满足条件的两个元组

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

(3)再在查询窗口2开始执行事务T2,修改学号为'202218014030'的学生的成绩为99,使用UPDLOCK锁

BEGIN TRAN T2
  UPDATE SC WITH(UPDLOCK)
  SET GRADE=99
  WHERE SNO='202218014030';

语句可以执行,说明事务T1读完数据后立刻释放了封锁

(4)返回事务T1继续运行事务,使用NOLOCK锁SC中SNO='202218014030'的元组,查询可执行,事务T1可读到事务T2修改后的数据,看到SC表中SNO='202218014030'的元组的GRADE值被更新,而事务T2没有提交,事务T1读取了脏数据

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(NOLOCK)
 WHERE SNO='202218014030';

 (5)事务T1继续执行,使用UPDLOCK锁,修改学号为‘202218014032’的学生的成绩为96,语句可以执行,说明事务T2只在SNO='202218014030'的元组上加上了更新锁

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(NOLOCK)
 WHERE SNO='202218014030';

 UPDATE SC WITH(UPDLOCK)
 SET GRADE=96
 WHERE SNO='202218014032';

(6)返回事务T2继续运行事务,使用TABLOCK锁,对SC表中SNO='202218014032'的元组进行查询,无结果显示,事务T2处于锁等待状态

BEGIN TRAN T2
  UPDATE SC WITH(UPDLOCK)
  SET GRADE=99
  WHERE SNO='202218014030';

  SELECT SNO,GRADE
  FROM SC WITH(TABLOCK)
  WHERE SNO='202218014032';

(7)返回事务T1提交事务,再返回事务T2可看到事务T2已执行,读取了事务T1提交后的数据,事务T2不会读取脏数据

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(NOLOCK)
 WHERE SNO='202218014030';

 UPDATE SC WITH(UPDLOCK)
 SET GRADE=96
 WHERE SNO='202218014032';
COMMIT TRAN T1;

(8)然后回滚事务T2,对事务T2中修改的元组进行查询,可见对SC表中SNO='202218014030'的元组的修改被撤销了,而已提交的事务T1已读取了事务T2中间修改过的值,读取了脏数据

BEGIN TRAN T2
  UPDATE SC WITH(UPDLOCK)
  SET GRADE=99
  WHERE SNO='202218014030';

  SELECT SNO,GRADE
  FROM SC WITH(TABLOCK)
  WHERE SNO='202218014032';
ROLLBACK
  SELECT *
  FROM SC
  WHERE SNO='202218014030';

5、通过前面两个并发事务的执行,可以看到

(1)SELECT语句加NOLOCK锁可以使并发操作立即执行,但会读取脏数据

(2)TABLOCK锁是一个短期读锁,可以避免读脏数据

(3)UPDLOCK锁是一个长期写锁 ,是细粒度锁,元组锁

6、下面来看另一组并发事务的执行

(1)在查询窗口1开始执行事务T1,还是首先使用TABLOCK锁,对关系表SC表中SNO='202218014030'的元组进行查询,仍然得到满足条件的3个元组

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 

(2)在查询窗口2执行更新语句,也就是一个隐式定义的事务,使用UPDLOCK锁修改修改学号为‘202218014030’的学生的成绩为99,语句可以执行,说明事务T1在读完数据后立刻释放了封锁

UPDATE SC WITH(UPDLOCK)
  SET GRADE=99
  WHERE SNO='202218014030';

 (3)返回事务T1继续运行事务,再次执行相同的查询操作,操作可执行,得到的查询结果与前一次查询结果不一样,说明短期读锁不具有可重复读特性

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

(4)若在事务T1将TABLOCK后加保持锁,再进行查询

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';
 
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK HOLDLOCK)
 WHERE SNO='202218014030';

 

(5)然后再在查询窗口2执行更新语句, 此时操作不再执行

UPDATE SC WITH(UPDLOCK)
  SET GRADE=99
  WHERE SNO='202218014030';

UPDATE SC WITH(UPDLOCK)
  SET GRADE=0
  WHERE SNO='202218014030';

(6)返回查询窗口1,在事务T1中再次执行前面的查询操作,查询结果不变,说明长期读锁具有可重复读特性

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';
 
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK HOLDLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK HOLDLOCK)
 WHERE SNO='202218014030';

(7)待事务T1提交后,查询窗口2中的操作才可执行

BEGIN TRAN T1
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK)
 WHERE SNO='202218014030';
 
 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK HOLDLOCK)
 WHERE SNO='202218014030';

 SELECT SNO,GRADE
 FROM SC WITH(TABLOCK HOLDLOCK)
 WHERE SNO='202218014030';
COMMIT TRAN T1

 

7、通过前面两个并发事务的执行可以看到

(1)使用TABLOCK锁,事务可以避免读脏数据,但数据不具有可重复读的特性 

(2)使用HOLDLOCK锁,可使TABLOCK锁变为长期读锁,可以保证数据的可重复读特性

8、多粒度封锁的实现

(1)DBMS为实现多粒度封锁,在事务对数据对象进行显示封锁的时候,并发控制机制为了更好地解决元组锁和关系锁之间的冲突,在给元组加锁前,要给元组所在的关系加一个意向锁

(2)意向锁的作用就是标识关系中某些元组正在被锁定其他用户将要锁定关系中的某些元组

(3)意向锁是由系统隐式进行添加的,不能人为干预

(4)根据事务要对数据对象要进行的读写操作不同,意向锁也有意向共享锁(IS)意向排他锁(IX)之分

(5)意向锁之间不会产生冲突互相兼容,与共享锁和排他锁间的兼容性,可见给出的锁相容矩阵

四、小结

1、运用多粒度封锁技术提高并发事务的并发程度

2、用户利用DBMS提供的多粒度封锁模式,根据应用需求,选择封锁粒度和封锁类型,通过显示地为事务中的操作加锁,可控制事务的并发执行

3、但在事务的并发执行过程中,多粒度封锁的灵活应用,在提高事务的并发程度的同时,也会带来数据的不一致问题用户需要根据事务对并发性和数据一致性的要求合理地使用锁

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

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

相关文章

SAP_MM模块-采购信息记录变更文档的三种查询方式

最近有用户在问采购信息记录变更的信息怎么去查找,想要看看是谁更改了价格,于是就给她查了一下,顺便做个记录,SAP中的业务数据或者主数据的变更信息查询方法,都是比较类似的,学会了这三个方法,其…

STM32介绍

本内容是基于江协科技STM32视频学习之后,并参考【重写】简析stm32启动过程-CSDN博客和STM32 最小系统_stm32最小系统-CSDN博客以及其他资料综合整理而成。 1. STM32 1.1 STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器;STM32常应用在…

TCP一定可靠吗

背景 公司某个服务发送TCP报文后,得到的响应是非预期数据 原因竟然是:TCP包的 payload 数据某个bit位被翻转,但是 checksum 的值一样,错误的包被分发给了上层服务 Checksum介绍 IP 头有自己的 Checksum,TCP、UDP 也有自己的 Checksum,分别校验不同部分的数据 IP 头的 …

【Linux系统】动态库和静态库 动态库加载

认识动态库静态库 我们有没有使用过库呢?-- 用过c、c的标准库 c的各种函数,c的各种STL容器,我们使用他们内部必须得有具体实现。 Linux: .so(动态库) .a(静态库) Windows: .dll(动态库) .lib(静态库) 库是拿来给别人使用的,所…

Spring源码十六:Bean名称转化

在上一篇Spring源码十五:Bean的加载 中我们通过前面的案例方法,找到了Spring真正开始创建Bean的入口,也就是doGetBean方法。该方法是Spring框架中Bean创建与获取的核心逻辑,实现了复杂的Bean生命周期管理。通过单例缓存、合并Bean…

文章解读与仿真程序复现思路——太阳能学报EI\CSCD\北大核心《计及电-热-氢负荷与动态重构的主动配电网优化调度》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【双一流高校主办,Springer-LNICST出版,EI稳定检索】2024年应用计算智能、信息学与大数据国际会议(ACIIBD 2024,7月26-28)

2024年应用计算智能、信息学与大数据国际学术会议(ACIIBD 2024)将于2024年7月26-28日在中国广州举办。会议将聚焦于计算智能及其应用、信息、大数据等相关的研究领域, 广泛邀请国内外知名专家学者,共同探讨相关学科领域的最新发展…

Maya崩溃闪退常见原因及解决方案

Autodesk Maya 是一款功能强大的 3D 计算机图形程序,被电影、游戏和建筑等各个领域的设计师广泛使用。然而,Maya 就像任何其他软件一样可能会发生崩溃问题。在前文中,小编给大家介绍了3ds Max使用V-Ray渲染时的崩溃闪退解决方案: …

电路基础知识汇总

1.0 串连,并联,混连 串联的定义 电路串联是一种电路元件的连接方式,其中各个元件沿着单一路径互相连接,形成一个连续的链。在串联电路中,每个节点最多只连接两个元件,这意味着电流只有一条路径可以通过整个…

“来来来,借一步说话”,让前端抓狂的可视化大屏界面。

可视化大屏的前端开发难度要远远高于普通前端,尤其是当设计师搞出一些花哨的效果,很容易让UI和前端陷入口水大战中。 可视化大屏的前端开发相比普通前端开发的难度要高,主要是因为以下几个方面: 1. 数据量大: 可视化…

01:spring

文章目录 一:常见面试题1:什么是Spring框架?1.1:spring官网中文1.2:spring官网英文 2:谈谈自己对于Spring IOC和AOP的理解2.1:IOCSpring Bean 的生命周期主要包括以下步骤: 2.2&…

STM32-输入捕获IC和编码器接口

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. 输入捕获IC1.1 输入捕获IC简介1.2 频率测量1.3 输入捕获通道1.4 主从触发模式1.5 输入捕获基本结构1.6 PWMI基本结构 2. 输入捕获库函数及代码2.1 输入捕获库函数2.2 6-6 输入捕获模式测频率2.2.1 硬件连接2.2.2 硬…

DevEco Studio无法识别本地模拟器设备的解决方法

目录 场景 解决办法 方式1 方式2 场景 有很多小伙伴遇到过安装了手机模拟器, 但是开发工具设备栏不识别手机设备的问题, 如下图,明明模拟器都安装了,并启动, 但为什么设备栏不显示呢? 解决后的截图,应该是这样(其实跟 android 类似 )

拓扑排序,PageRank(markov),实对称矩阵等

拓扑排序 多件事情有先后顺序,如何判断哪个先哪个后 拓扑排序算法: 1.读入图时,需要记录每个顶点的入度,以及相邻的所有顶点 2.将入度为0的顶点入队(先进先出) 3.取出队首元素a,&#xf…

检测到弱密码:并非所有密码套件均支持完全前向保密解决方案

问题 检测到弱密码:并非所有密码套件均支持完全前向保密(弱密码套件 - ROBOT 攻击:服务器支持易受攻击的密码套件) 背景介绍 HTTP 协议自身没有加密机制,但可以通过与 TLS (Transport Layer Security) / SSL (Secur…

QThread moveToThread的妙用

官方文档描述 总结就是移动到线程的对象不能有父对象,执行start即起一个线程,示例是将myObject移动到主线程中。QT中这种方式起一个线程是非常简单的。 示例描述以及代码 描述往Communicate线程中频繁添加任务,等任务结束的时候统计计算的结…

用C#调用Windows API向指定窗口发送按键消息详解与示例

文章目录 1. 按键消息的定义及功能2. 引入所需的命名空间3. 定义Windows API函数4. 定义发送消息的方法5. 获取窗口句柄6. 调用API发送按键消息7. 使用示例注意事项总结 在C#中调用Windows API向指定窗口发送按键消息是一种常见的操作,这通常用于自动化脚本、游戏辅…

中国科学技术大学发布了2024年少年班录取名单

7月7日,中国科学技术大学发布了2024年少年班录取名单公示,来自上海的12岁“小孩哥”刘尧进入名单。 据澎湃新闻此前报道,刘尧是因为此前通过了中科大少年班的校测考试,提前拿到了“高考体验券”。他所在的上海市实验学校&#xff…

Vue3+.NET6前后端分离式管理后台实战(二十九)

1,Vue3.NET6前后端分离式管理后台实战(二十九)

go语言Gin框架的学习路线(六)

gin的路由器 Gin 是一个用 Go (Golang) 编写的 Web 框架,以其高性能和快速路由能力而闻名。在 Gin 中,路由器是框架的核心组件之一,负责处理 HTTP 请求并将其映射到相应的处理函数上。 以下是 Gin 路由器的一些关键特性和工作原理的简要解释…