【数据库】并发控制
并发控制
在数据库系统,经常需要多个用户同时使用。同一时间并发的事务可达数百个,这就是并发引入的必要性。
常见的并发系统有三种:
- 串行事务执行(X),每个时刻只有一个事务运行,不能充分利用系统资源
- 交叉并发(V),并行事务并行操作轮流交叉运行,适应于单处理机系统,能够减少处理机的空闲时间,提高系统的效率。
- 同时并发,多个处理机同时运行多个事务,理想的并发方式,但是受限于硬件环境。

但是并发控制可能导致一些问题,所以主要有三个任务:
- 对并发操作的正确调度
- 保证事务隔离性
- 保证数据库的一致性
并发操作的后果
并发控制可能导致的数据不一致性有三类:
- 丢失修改
- 不可重复读
- 读脏数据
为了说明这三种情况,我们用 R ( x ) R(x) R(x)表示读数据 x x x, W ( x ) W(x) W(x)表示写数据 x x x.
一、丢失修改
考虑下面的情况:
T 1 T_1 T1 | T 2 T_2 T2 |
---|---|
R ( A ) = 16 R(A)=16 R(A)=16 | |
R ( A ) = 16 R(A)=16 R(A)=16 | |
A = A − 1 , W ( A ) = 15 A=A-1,W(A)=15 A=A−1,W(A)=15 | |
A = A − 1 A=A-1 A=A−1, W ( A ) = 15 W(A)=15 W(A)=15 |
那么 T 1 T_1 T1对 A A A的修改丢失了。
二、不可重复读
不可重复读是在 T 1 T_1 T1读取数据后, T 2 T_2 T2更新,导致 T 1 T_1 T1无法再现读取结果。
(1)RUR(Read, Update, Read)
T 1 T_1 T1 | T 2 T_2 T2 |
---|---|
R ( A ) = 50 , R ( B ) = 100 , S = 150 R(A)=50,R(B)=100, S=150 R(A)=50,R(B)=100,S=150 | |
R ( B ) = 100 , W ( B ) = 200 R(B)=100, W(B)=200 R(B)=100,W(B)=200 | |
R ( A ) = 50 , R ( B ) = 200 , S = 250 R(A)=50,R(B)=200, S=250 R(A)=50,R(B)=200,S=250 |
(2)RDR(Read, Delete, Read)
T 1 T_1 T1 | T 2 T_2 T2 |
---|---|
R ( A ) = 50 , R ( B ) = 100 , S = 150 R(A)=50,R(B)=100, S=150 R(A)=50,R(B)=100,S=150 | |
将B记录从数据库中删除 | |
无法读取到B的记录 |
(3)RAR(Read, Add, Read)
T 1 T_1 T1 | T 2 T_2 T2 |
---|---|
A中有两条记录, ∑ A i = 100 \sum A_i = 100 ∑Ai=100 | |
将记录50插入到集合A中 | |
A中有三条记录, ∑ A i = 150 \sum A_i = 150 ∑Ai=150 |
三、读脏数据
事务 T 1 T_1 T1修改某一数据,并写回磁盘,然后 T 2 T_2 T2读取之后, T 1 T_1 T1因为某种原因被撤销,这个时候 T 2 T_2 T2的数据可能不一致。
T 1 T_1 T1 | T 2 T_2 T2 |
---|---|
R ( C ) = 100 , W ( C ) = 200 R(C)=100, W(C)=200 R(C)=100,W(C)=200 | |
R ( C ) = 200 R(C)=200 R(C)=200 | |
ROLLBACK C,C恢复为100 |
封锁
一、封锁的概念
封锁是指事务在某个数据对象操作前先对系统请求进行加锁。加锁之后,事务就有了数据对象控制权。
基本封锁类型有两种:排它锁(Exclusive Locks, X锁)和共享锁(Share Locks, S锁)
排它锁又称写锁,如果 T T T对 A A A加X锁,那么其它事务不能加任何其他锁。这个时候,其它事务不能读取和修改。
共享锁又称读锁,如果 T T T对 A A A加S锁,那么其它事务只能对 A A A加 S S S锁。这个时候,其它事务可以读 A A A,但是在 T T T释放锁之前不能进行修改。
换言之,存在锁的相容矩阵:

二、封锁协议
申请锁、持有锁、释放锁的规则,叫做封锁协议。
一级封锁协议是事务中队数据修改之前必须对其加排它锁直到事务结束。
一级封锁协议可以有效防止丢失更新。

二级封锁协议是在一级协议的基础上,要求读取数据之前必须加共享锁,读完再释放。这样可以防止读脏数据。
二级封锁协议可以有效防止读脏数据。

三级封锁协议是在二级基础上,增加某事务施加的共享锁,保持到事务结束再释放。
三级封锁协议可以解决不可重复得问题。

活锁和死锁
一、活锁
考虑有四个事务T1,T2,T3,T4
T1封锁数据R,T2请求R,所以T2等待。T3也请求R,然后T1释放R的锁之后系统调度给T3,T4请求R,T3释放R的锁之后系统调度给T4,导致T2永远等待。这就是活锁。

避免活锁比较简单,只需要采取先来先服务的策略,在多个事务请求封锁同一个数据对象的时候按照请求封锁的先后次序对事务排序。
二、死锁
考虑两个事务T1、T2。T1封锁R1,T2封锁R2。T1此时请求封锁R2,而T2封锁R2,所以T1等待T2释放R2的锁。此时T2又申请R1,T1已经封锁R1,T2只能等待T1释放R1的锁。此时,T1、T2形成死锁。

如果希望预防死锁,一般有两个思路:
- 一次封锁法。要求每个事务必须一次将所有要使用的数据全部 加锁,否则就不能继续执行。但是这样比较难确定封锁对象,也会导致并发度降低。
- 顺序封锁法。对数据对象规定封锁顺序,按照顺序进行封锁。但是这样难以确定事务要封锁哪些对象。
因此,死锁的预防比较难,多采用诊断解决的思路。
最简单的诊断方法就是使用超时法,如果事务等待时间超过规定时限,就说明发生死锁。这样实现简单,但是可能误判,并且如果时限过长,可能会让死锁无法及时发现。
等待图法是一个比较好的方式。设 G = ⟨ V , E ⟩ G=\langle V,E\rangle G=⟨V,E⟩, V V V是正运行的事务, E E E是事务等待情况,如果 T 1 T_1 T1等待 T 2 T_2 T2,就连接 T 1 T 2 T_1T_2 T1T2。如果图中存在回路,说明系统出现死锁。

检测到死锁后,选择一个处理死锁代价最小的事务,将其撤销。释放事务持有的所有锁,让其他事务能运行下去。
可串行性
多个事务的并发执行想要保证正确性,需要结果和某一次序串行执行结果相同。
一、可串行化的判定
可串行性是并发事务正确调度的准则,只有并发调度是可串行化的才能认为是正确调度。
考虑下面的两个事务:
- T1:读B,A=B+1,写回A
- T2:读A,B=A+1,写回B
对于下面的这些策略:


这两种策略相当于串行执行,因此并行执行的结果应当和二者之一相同。而对于下面的例子:

不可串行化。
二、冲突可串行化
冲突可串行化给出了一个可串行化的充分条件:
一个调度Sc在保证冲突操作次序不变的情况下,通过交换两个事务不冲突操作的次序得到另一个调度Sc’。如果Sc’是串行的,称调度Sc为冲突可串行化的调度。
这里需要先引入冲突操作的概念。所谓冲突操作是指如下操作:
- 事务Ti读x,Tj写x
- 事务Ti写x,Tj写x
下面举一个例子。
证明:调度Sc1=r1(A)w1(A)r2(A)w2(A)r1(B)w1(B)r2(B)w2(B)可串行化。
r1(A)、w1(A)、w2(A)不可交换,r1(B)、w1(B)、w2(B)不可交换。
这样,可以交换为r1(A)w1(A)r1(B)w1(B)r2(A)w2(A)r2(B)w2(N)
这是一个串行调度T1T2,所以Sc1是冲突可串行化调度。
需要注意的是,这个条件并不是必要的。下面举一个反例。
T1=W1(Y)W1(X), T2=W2(Y)W2(X), T3=W3(X)
调度W1(Y)W2(Y)W2(X)W1(X)W3(X)结果与T1T2T3相同,可串行化,但并非冲突可串行化。
两段锁
在封锁的时候,对数据对象加锁需要遵守约定,比如何时申请加锁、锁持续时间和何时释放。两段封锁协议(2PL)是最常用的封锁协议,并且能产生可串行化调度。
两段锁协议是指所有事务需要分两个阶段对数据项加锁和解锁:
- 在数据读写之前,事务需要先取得封锁
- 释放封锁之后,事务不再申请和获得其它封锁
这里的两段,具体来说就是事务的两个阶段:
- 扩展阶段,获得封锁,可以申请获得数据项上任何类型的锁,但是不能释放任何锁
- 收缩阶段,释放封锁,可以释放任何数据线上的任何类型的锁,但是不能申请任何锁。
比如事务A按照两段锁协议的封锁序列是:
Slock A, Slock B, Xlock C, Unlock B, Unlock A, Unlock C
如果多个调度都符合两段锁协议,一定是一个可串行化调度。

但是两段锁可能会出现死锁,所以还需要引入一次封锁法。也就是事务必须一次将所有使用数据全部加锁,否则就不能继续执行,这样可以回避死锁。
封锁粒度
封锁对象的大小称为封锁粒度。封锁对象分成逻辑单元和物理单元。
在关系数据库中,逻辑单元包括属性值、属性值集合、元组、关系、索引项、整个索引、整个数据库;物理单元包括页和物理记录。
封锁粒度和系统并发度与并发控制的开销密切相关。
- 粒度大,封锁数据单元少,并发度低,开销小
- 粒度小,并发度高,开销大
下面举两个例子。
(1)若封锁粒度是数据页,事务T1需要修改元组L1,则T1必 须对包含L1的整个数据页A加锁。如果T1对A加锁后事务T2要修改A中元组L2,则T2被迫等待,直到T1释放A。如果封锁粒度是元组,则T1和T2可以同时对L1和L2加锁,不需要互相等待,提高了系统的并行度。
(2)事务T需要读取整个表,若封锁粒度是元组,T必须对表中的每一个元组加锁,开销极大。
因此,在一个系统中需要同时支持多种封锁粒度供不同事务选择,也就是 多粒度封锁。在选择粒度的时候,要同时考虑封锁开销和并发度:
- 对处理多个关系大量元组的事务,以数据库为封锁单位
- 对处理大量元组的事务,以关系为封锁单位
- 对少量元组的用户事务,以元组为封锁单位。
可以用一颗树来表示粒度,称作多粒度树:

在这个树中,对一个结点加锁相当于节点所有子孙加同类型的锁。这里就引入了显式封锁和隐式封锁:显式封锁是直接加到数据对象上的封锁,隐式封锁是由于上级结点加锁导致的子节点加锁。
因此,系统在检查封锁冲突的收,需要检查显式封锁和隐式封锁。具体来说就是:
- 数据对象有没有显式封锁与之冲突
- 本事务显式封锁是否与上级节点隐式封锁冲突
- 上面的显式封锁是否与本事务隐式封锁冲突
意向锁
在此基础上,引入意向锁,来提高对某个数据对象加锁时系统的检查效率。
如果对一个结点加意向锁,说明其下层节点正在被加锁;对任意结点加基本锁,必须对上层节点加意向锁。
常用的意向锁有三种:
- 意向共享锁(IS锁),表示后裔节点拟(意向)加S锁
- 意向排它锁(IX锁),表示后裔节点拟(意向)加X锁
- 共享意向排它锁(SIX锁),表示对它加S锁,再加IX锁。
对于这些锁,相容矩阵如下:

锁强度的哈斯图如下:

这里锁强度是对其他所的排斥程度,强锁对弱锁是安全的。
在引入意向锁之后,执行封锁操作:
- 申请时按照从上到下的次序
- 释放时按照从下到上的次序
例如,T1对R1加S锁,需要下面的操作
- 对数据库加IS锁
- 检查数据库和R1是否加了不相容锁,也就是X或IX锁
- 无需搜索R1中元组是否加了X锁。
这样,意向锁提高了系统并发度,减少了加减锁的开销,得到广泛应用。
相关文章:

【数据库】并发控制
并发控制 在数据库系统,经常需要多个用户同时使用。同一时间并发的事务可达数百个,这就是并发引入的必要性。 常见的并发系统有三种: 串行事务执行(X),每个时刻只有一个事务运行,不能充分利用…...

Ansys Zemax | 手机镜头设计 - 第 2 部分:光机械封装
本文该系列文章将讨论智能手机镜头模组设计的挑战,涵盖了从概念、设计到制造和结构变形的分析。本文是四部分系列的第二部分,介绍了在 Ansys Speos 环境中编辑光学元件以及在整合机械组件后分析系统。案例研究对象是一家全球运营制造商的智能手机镜头系统…...
湖北理元理律师事务所债务优化实践:在还款与生活间寻找平衡支点
在个人债务规模持续扩大的社会背景下,如何科学管理债务正成为民生焦点。湖北理元理律师事务所通过其服务案例表明:债务优化的本质不是逃避责任,而是建立可持续的还款体系,让债务人保有基本生活尊严。 一、打破“越还越穷”的恶性…...

mcp-go v0.30.0重磅发布!Server端流式HTTP传输、OAuth支持及多项功能革新全面解读!
随着云原生应用和现代分布式系统需求的不断增长,高效、灵活且稳定的通信协议和客户端交互框架成为开发者关注的焦点。作为开源领域备受期待的项目之一,mcp-go再次迎来重要版本更新——v0.30.0正式发布!本次更新版本不仅实现了众多关键功能&am…...
解锁 MCP 中的 JSON-RPC:跨平台通信的奥秘
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等希望看什么,评论或者私信告诉我! 文章目录 零、 背景一、RPC vs HTTP1.1 什么是RPC1.2 为什么需要 RPC?1.3 RPC 解决了什么…...
流复制(Streaming Replication)与自动故障转移(Failover)实战:用Patroni或Repmgr搭建生产级数据库集群
更多服务器知识,尽在hostol.com 嘿,各位PostgreSQL的“掌舵人”和数据“守护神”们!咱们都知道,PostgreSQL(简称PG)以其强大的功能、稳定性和开源的特性,赢得了越来越多开发者和企业的青睐。但…...

OpenGL Chan视频学习-10 Dealing with Errors in OpenGL
bilibili视频链接: 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 函数网站: docs.gl 说明: 1.之后就不再单独整理网站具体函数了,网站直接翻译会…...

美团启动618大促,线上消费节被即时零售传导到线下了?
首先,从市场推广与消费者吸引的角度来看,美团通过联合众多品牌开展大规模促销活动,并发放高额优惠券包,旨在吸引更多消费者参与购物。这种策略有助于提高平台的活跃度和交易量,同时也能够增强用户粘性。对于消费者而言…...

搭建 Select 三级联动架构-东方仙盟插件开发 JavaScript ——仙盟创梦IDE
三级级联开卡必要性 在 “东方仙盟” 相关插件开发中,使用原生 HTML 和 JavaScript 实现三级联动选择(如村庄 - 建筑 - 单元的选择)有以下好处和意义,学校管理: 对游戏体验的提升 增强交互性:玩家能够通…...

服务器如何配置防火墙管理端口访问?
配置服务器防火墙来管理端口访问,是保障云服务器安全的核心步骤。下面我将根据你使用的不同操作系统(Linux: Ubuntu/Debian/CentOS;Windows Server)介绍常用防火墙配置方法。 ✅ 一、Linux 防火墙配置(UFW / firewalld…...
Webhook入门
主要参考资料: 深入解析 Webhook:从原理到实践的全面指南: https://blog.csdn.net/weixin_43114209/article/details/144250750 目录 简介Webhook 与传统 API 调用的区别与轮询 (Polling) 的对比典型工作流程 简介 简单来说,Webhook 是一种“…...
LangChain整合Milvus向量数据库实战:数据新增与删除操作
导读:在AI应用开发中,向量数据库已成为处理大规模语义搜索和相似性匹配的核心组件。本文通过详实的代码示例,深入探讨LangChain框架与Milvus向量数据库的集成实践,为开发者提供生产级别的向量数据管理解决方案。 文章聚焦于向量数…...
LSTM+Transformer混合模型架构文档
LSTMTransformer混合模型架构文档 模型概述 本项目实现了一个LSTMTransformer混合模型,用于超临界机组协调控制系统的数据驱动建模。该模型结合了LSTM的时序建模能力和Transformer的自注意力机制,能够有效捕捉时间序列数据中的长期依赖关系和变量间的复…...
Symbol、Set 与 Map:新数据结构探秘
Symbol、Set 与 Map:新数据结构探秘 引言 ECMAScript 6 (ES6) 引入了三种强大的数据结构:Symbol、Set 与 Map,它们解决了 JavaScript 开发中的特定痛点,为我们提供了更多工具来处理复杂的数据操作。 Symbol:唯一标识…...

Spring Boot+Activiti7入坑指南初阶版
介绍 Activiti 是一个轻量级工作流程和业务流程管理 (BPM) 平台,面向业务人员、开发人员和系统管理员。其核心是一个超快且坚如磐石的 Java BPMN 2 流程引擎。它是开源的,并根据 Apache 许可证分发。Activiti 可以在任何 Java 应用程序、服务器、集群或云中运行。它与 Spri…...

如何在 Odoo 18 中创建 PDF 报告
如何在 Odoo 18 中创建 PDF 报告 Qweb 是 Odoo 强大的模板引擎,旨在轻松将 XML 数据转换为 HTML 文档。其功能特性包括基于属性的自定义、条件逻辑、动态内容插入及多样化的报告模板选项。这种多功能性使 Qweb 成为制作个性化、视觉吸引力强的报告、电子邮件和文档…...

【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用
【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用 文章目录 前言正文配置环境下载源码配置环境变量测试运行修改点说明实际运行情况 参考 前言 本文用来记录 xCoreSDK-Python的调用使用1。 正文 配置环境 配置开发环境,这里使用conda做python环境管理&…...
c/c++的opencv椒盐噪声
在 C/C 中实现椒盐噪声 椒盐噪声(Salt-and-Pepper Noise),也称为脉冲噪声(Impulse Noise),是数字图像中常见的一种噪声类型。它的特点是在图像中随机出现纯白色(盐)或纯黑色&#x…...
C++ TCP程序增加TLS加密认证
TCP为什么要增加TLS TCP程序添加TLS主要是为了解决TCP协议本身的安全缺陷。TCP作为传输层协议,虽然提供了可靠的数据传输,但它是明文传输,存在几个关键的安全问题: 数据泄露风险:TCP传输的数据完全暴露在网络中,任何能够监听网络流量的人都可以直接读取传输内容。这对于…...
构建一个“论文检索 + 推理”知识库服务,支持用户上传 PDF/LATEX 源码后,秒级检索并获得基于内容的问答、摘要、引用等功能
文章目录 1 总体目标 / Overall Goal2 数据管线 / Data Pipeline3 检索策略 / Retrieval Strategy4 服务切分 / Service Decomposition5 Agent & Prompt 设计 / Agent & Prompt6 核心功能 / Core Features7 评测与监控 / Evaluation & Monitoring8 面试亮点 / Inte…...

VLC-QT 网页播放RTSP
先看效果图,代码在文章末尾,包含源码,vlc-qt完整的库 环境说明:VS 2017 QTQt5.13.0 MSVC2017 32位 将vlc_install 目录下的bin,include,lib里所有的东西分别放在qt目录下 bin -> C:\Qt\Qt5.13.0\5.13.0\msvc2017\bin include->C:\Qt\Qt5.13.0\5.13.0\msvc201…...
for(auto a:b)和for(auto a:b)的区别
#include<iostream> using namespace std; int main() {string s( "hello world" );for (auto c:s)c t ;cout<<s<<endl; //结果为hello worldfor (auto &c:s)c t ;cout<<s<<endl; //结果为ttttttttttt }for(auto a:b)中b为一…...
第2章-12 输出三角形面积和周长(走弯路解法)
本题要求编写程序,根据输入的三角形的三条边a、b、c,计算并输出面积和周长。注意:在一个三角形中, 任意两边之和大于第三边。三角形面积计算公式:areas(s−a)(s−b)(s−c),其中s(abc)/2。 import math de…...
Caddy如何在测试环境中使用IP地址配置HTTPS服务
前言 在开发和测试环境中,我们经常需要搭建HTTPS服务进行测试。但通常Let’s Encrypt等证书颁发机构要求使用有效域名,不直接支持IP地址。本文将详细介绍如何使用Caddy在测试环境中通过IP地址配置HTTPS服务,使用自签名证书解决这一问题。 环…...
shell中与>和<相关的数据流重定向操作符整理
shell中与>和<相关的数据流重定向操作符整理 输出重定向操作符>>>2>2>>&> 或 >&&>> 输入重定向操作符<<<<<< 组合重定向2>&1 文件描述符相关重定向[n]< file 和 [n]> file>&- 和 <&…...

【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix
【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix 文章目录 【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix一、资料准备1.去畸变影像2.相机文件3.外方位元素二、创建工程1.新建工程2.导入照片3.编辑相机文件4.编辑外方位元素文件,导入外方位元…...

创建型设计模式之Prototype(原型)
创建型设计模式之Prototype(原型) 摘要: Prototype(原型)设计模式通过复制现有对象来创建新对象,避免重复初始化操作。该模式包含Prototype接口声明克隆方法、ConcretePrototype实现具体克隆逻辑ÿ…...

JNI开发流程
一. 引言 最近在做一个自己的项目,就是基于FastDDS封装一套JAVA库,让android和java应用可以使用dds的功能。 由于FastDDS是使用C编写的开源库,因此java的类库想要调用FastDDS的接口,需要额外编写一个JNI层的动态库对FastDDS的接口…...

STM32G4 电机外设篇(二) VOFA + ADC + OPAMP
目录 一、STM32G4 电机外设篇(二) VOFA ADC OPAMP1 VOFA1.1 VOFA上位机显示波形 2 ADC2.1 用ADC规则组对板载电压和电位器进行采样 3 OPAMP(运放)3.1 结合STM32内部运放和ADC来完成对三相电流的采样3.2 运放电路分析 附学习参考…...
RAG应用:交叉编码器(cross-encoder)和重排序(rerank)
文章目录 Sentence Transformers交叉编码器交叉编码器使用示例检索和重排序Sentence Transformers Sentence Transformers 支持两种类型的模型: Bi-encoders 和 Cross-encoders。Bi-encoders 更快更可扩展,但 Cross-encoders 更准确。虽然两者都处理类似的高水平任务,但何时…...