数据库的并发控制
并发控制
12.1 并发级别
问题:交错的读写
并发客户端可以随意进入和退出事务,并在中途请求读取和写入。为了简化分析,假设enter/exit/read/write
是原子步骤,因此并发事务只是这些步骤的交错。
我们还将区分只读事务和读写事务:
- 并发读者比并发写者更容易处理。
- 许多应用程序是读密集型的,因此读性能更为重要。
读者-写者锁(RWLock)
如果不了解如何实现并发控制,可以简单地添加一个互斥锁(mutex)来序列化数据访问。为了提升读性能,可以使用读者-写者锁(RWLock),它允许多个并发读者,但只有一个写者。
- 如果没有写者,数据不会改变,因此并发读者是可以接受的。
- 当写者想要进入时,它会等待所有读者离开。
- 写者会阻塞读者,但读者之间不会相互阻塞。
这种方法的用处有限,因为写者之间没有并发能力,且长时间运行的事务会导致读者和写者互相阻塞。
读-复制-更新(RCU)
为了防止读者和写者互相阻塞,可以让读者和写者各自操作自己的数据版本:
- 数据有一个指向不可变数据的指针,读者只需抓取快照。
- 单个写者更新自己的副本,然后翻转指针。
由于我们采用的是写时复制(copy-on-write),这种并发级别是免费获得的。然而,单个写者仍然不足,因为事务的生命周期由客户端控制,可能任意延长。
乐观并发控制
并发写者会导致冲突,例如:
SeqTX1:
read a
write b := a
commitSeqTX2:
write a := 1
commit
TX1依赖于TX2修改的同一键,因此它们不能同时成功。
有些看似“仅写”的操作实际上有读依赖性。例如,我们的更新/删除接口会报告键是否被更新或删除,这取决于键的先前状态。因此以下场景也是冲突:
SeqTX1:
write a := 1
commitSeqTX2:
delete a
commit
一种解决冲突的方法是在检测到冲突时中止事务:
- 事务开始。
- 读取基于快照,但写入缓冲在本地。
- 提交前验证与已提交事务是否有冲突。
- 事务结束:
- 如果有冲突,中止并回滚。
- 否则,将缓冲的写入转移到数据库。
验证和提交是一个原子步骤。这种方法称为乐观并发控制,因为它假设冲突很少发生,因此不采取任何措施预防冲突。
悲观并发控制(替代方法)
在乐观并发控制中,事务在冲突时无法继续,这对应用程序来说并不友好,因为它们只能不断重试。另一种解决冲突的方法是通过锁定来预防冲突。事务会为其依赖项获取锁,潜在冲突的事务会彼此等待。
这种方法听起来更好,尤其是在最后一个示例中,写/删操作可以无问题地进行。然而,这仍然不能保证进展,因为事务可能会因死锁而失败。
死锁是指两个参与者彼此等待对方释放自己持有的锁。如果依赖图中存在循环,超过两个参与者也可能发生死锁。在并发编程中,锁应按预定义顺序获取以避免循环。但对于数据库而言,客户端可以以任意顺序获取锁,因此数据库必须检测并解决死锁,这是一个图问题。
12.2 为读者实现快照隔离
隔离级别指的是事务如何看待其他事务的更改。对于写时复制来说这不是问题,因为每个事务都操作B+树的快照。
捕获本地更新
事务保持数据库的快照和本地更新:
- 快照只是一个根指针(写时复制)。
- 本地更新保存在一个内存中的B+树中。
type KVTX struct {snapshot BTree // 只读快照pending BTree // 捕获的KV更新,值通过1字节标志表示删除的键
}
快照和本地更新都在事务开始时初始化:
func (kv *KV) Begin(tx *KVTX) {tx.snapshot.root = kv.tree.roottx.snapshot.get = ... // 从mmap页面读取pages := [][]byte(nil)tx.pending.get = func(ptr uint64) []byte { return pages[ptr-1] }tx.pending.new = func(node []byte) uint64 {pages = append(pages, node)return uint64(len(pages))}tx.pending.del = func(uint64) {}
}
读取自己的写入
在事务内,客户端应该能够读取刚刚写入的内容,即使尚未提交。查询应先检查KVTX.pending
再检查KVTX.snapshot
。这就是为什么写入保存在B+树中而不是列表中。
func (tx *KVTX) Get(key []byte) ([]byte, bool) {val, ok := tx.pending.Get(key)switch {case ok && val[0] == FLAG_UPDATED: // 在此事务中更新return val[1:], truecase ok && val[0] == FLAG_DELETED: // 在此事务中删除return nil, falsecase !ok: // 从快照中读取return tx.snapshot.Get(key)default:panic("unreachable")}
}
对于范围查询,新增了一个迭代器类型来合并两棵树。
空闲列表中的版本号
由于读者可能持有旧版本的数据库,空闲列表不能释放这些版本中的页面。我们通过为每个版本分配单调递增的版本号(也称为时间戳)来解决这个问题。
type FreeList struct {maxVer uint64 // 最老的读者版本curVer uint64 // 提交时的版本号
}
12.3 处理写者的冲突
检测历史冲突
所有读取都被添加到KVTX.reads
中(点查询和范围查询)。
type KVTX struct {reads []KeyRange
}
每次成功提交都会添加到KV.history
中。
type KV struct {history []CommittedTX
}
冲突检测通过检查依赖关系和历史记录之间的重叠来进行:
func detectConflicts(kv *KV, tx *KVTX) bool {for i := len(kv.history) - 1; i >= 0; i-- {if !versionBefore(tx.version, kv.history[i].version) {break}if rangesOverlap(tx.reads, kv.history[i].writes) {return true}}return false
}
代码仓库地址:database-go
序列化内部数据结构
在分析中,事务被简化为交错的步骤。在现实中,这些步骤可以并行运行,因此需要序列化共享的KV结构。
type KV struct {mutex sync.Mutex
}
尽管可以通过锁保护所有KVTX方法,但也可以减少锁定。例如:
- 写入仅操作
KVTX.pending
,不会触及KV。 - 读取仅触及
KV.mmap.chunks
,这是mmap
返回的切片。
提交步骤可能会修改KV.mmap.chunks
,因此每个事务使用一个本地副本。
通过这种方式,读写方法不需要加锁,并且可以并行运行。这很好,因为读取操作可能会触发页面错误(page faults)并阻塞线程。
到目前为止,只有Begin
、Commit
和Abort
是序列化的。但考虑到Commit
涉及I/O操作,我们可以通过在等待I/O时释放锁来进一步优化,以允许其他事务进入,并让只读事务退出。提交步骤仍然需要通过另一个锁与其他提交步骤序列化。这一点留作练习。
相关文章:
数据库的并发控制
并发控制 12.1 并发级别 问题:交错的读写 并发客户端可以随意进入和退出事务,并在中途请求读取和写入。为了简化分析,假设enter/exit/read/write是原子步骤,因此并发事务只是这些步骤的交错。 我们还将区分只读事务和读写事务…...
力扣第448场周赛
赛时成绩如下: 这应该是我力扣周赛的最好成绩了(虽然还是三题) 1. 两个数字的最大乘积 给定一个正整数 n。 返回 任意两位数字 相乘所得的 最大 乘积。 注意:如果某个数字在 n 中出现多次,你可以多次使用该数字。 示例 1: 输入࿱…...
关于Python:9. 深入理解Python运行机制
一、Python内存管理(引用计数、垃圾回收) Python(CPython)采用的是: “引用计数为主,垃圾回收为辅” 的内存管理机制。 也就是说: 引用计数机制:负责大部分内存释放,简…...
Cron表达式的用法
最近几天开发东西用到了定时脚本的问题,中间隔了一段时间没有用到,再次复习一下Cron表达式的用法。 Cron表达式是一种用于定义定时任务执行时间的字符串格式,广泛应用于Unix/Linux系统以及各种编程语言中。其主要用途是通过灵活的时间规则来…...
手机通过局域网访问网狐接口及管理后台网站
1.本地部署接口及后台网站 2.设置允许网站端口通过防火墙 3.查看网站服务器IP 4.手机连接到本地服务器同一局域网 5.手机访问本地服务器接口...
JavaSE核心知识点01基础语法01-01(关键字、标识符、变量)
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 JavaSE核心知识点01基础语法01-01࿰…...
Sliding Window Attention(Longformer)
最简单的自注意力大家肯定都会啦。 但这种全连接的自注意力(即每个 token 需要 attend 到输入序列中的所有其他 token)计算与内存开销是 O ( n 2 ) O(n^2) O(n2) 。为了缓解这个问题,研究者们提出了 Sliding Window Attention。 Sliding W…...
ROS2 开发踩坑记录(持续更新...)
1. 从find_package(xxx REQUIRED)说起,如何引用其他package(包) 查看包的安装位置和include路径详细文件列表 例如,xxx包名为pluginlib # 查看 pluginlib 的安装位置 dpkg -L ros-${ROS_DISTRO}-pluginlib | grep include 这条指令的目的是…...
刷leetcodehot100返航版--哈希表5/5、5/6
回顾一下之前做的哈希,貌似只有用到 unordered_set:存储无序元素unordered_map:存储无序键值对 代码随想录 常用代码模板2——数据结构 - AcWing C知识回顾-CSDN博客 1.两数之和5/5【30min】 1. 两数之和 - 力扣(LeetCode&am…...
嵌入式开发学习日志Day13
第九章 预处理命令 前面加“#”的都为预处理命令; 预处理命令是无脑的文本替换; 一、宏定义 1、不带参数的宏定义 一般形式为: #define 标识符 字符串 (谷歌规定):所有的宏名均大写,便于…...
AI预测的艺术品走势靠谱吗?
首席数据官高鹏律师团队 AI预测艺术品价格走势:技术与法律的双重考量在当今数字化浪潮席卷全球的时代,人工智能(AI)技术正以前所未有的速度渗透到各个领域,艺术品市场也不例外。AI预测艺术品价格走势这一新兴事物&…...
AVL树 和 红黑树 的插入算法
1.AVL树 按照二叉搜索树的规则找到要插入的位置并插入,插入过后看是父节点的左还是右孩子,然后把父节点的平衡因子-1或1,调整后如果父节点的平衡因子是0,那就说明这颗子树的高度插入前后不变,上面的就不用调整平衡因子…...
【项目】基于ArkTS的网吧会员应用开发(1)
一、效果图展示 二、界面讲解 以上是基于ArkTS的鸿蒙应用网吧会员软件的引导页,使用滑动组件滑动页面,至最后一页时,点击立即体验,进入登录页面。 三、代码演示 import promptAction from ohos.promptAction; import router fr…...
命令模式(Command Pattern)
非常好!现在我们来深入讲解行为型设计模式之一 —— 命令模式(Command Pattern)。 我将通过: ✅ 定义解释 🎯 使用动机 🐍 Python 完整调用代码(含注释) 🧭 清晰类图 …...
CMake基础介绍
1、CMake 概述 CMake 是一个项目构建工具,并且是跨平台的;关于项目构建目前比较流行的还有 Makefile(通过 Make 命令进行项目的构建), 大多 IDE 软件都集成了 make,比如:VS 的 nmake、linux 下的 GNU make、Qt 的 qmake 等&…...
偷钱包行为检测数据集VOC+YOLO格式922张1类别有增强
有320张图片是原图剩余为增强图片 数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):922 标注数量(xml文件个数):922 标注数量…...
C 语言比较运算符:程序如何做出“判断”?
各类资料学习下载合集 https://pan.quark.cn/s/8c91ccb5a474 在编写程序时,我们经常需要根据不同的条件来执行不同的代码。比如,如果一个分数大于 60 分,就判断为及格;如果用户的年龄小于 18 岁,就禁止访问某个内容等等。这些“判断”的核心,就依赖于程序能够比…...
Webug4.0靶场通关笔记16- 第20关文件上传(截断上传)
目录 第20关 文件上传(截断上传) 1.打开靶场 2.源码分析 (1)右键查看前端源码 (2)服务端源码分析 (3)渗透思路 3.渗透实战 (1)构建脚本 (2)bp抓包 …...
10 种最新的思维链(Chain-of-Thought, CoT)增强方法
防御式链式思维(Chain-of-Defensive-Thought) 该方法通过引入结构化、防御性的推理示例,提高大语言模型在面对被污染或误导信息时的稳健性。 📄 论文链接:https://arxiv.org/abs/2504.20769 混合链式思维(…...
力扣119题解
记录 2025.5.5 题目: 思路: 代码: class Solution {public List<Integer> getRow(int rowIndex) {List<Integer> row new ArrayList<Integer>();row.add(1);for (int i 1; i < rowIndex; i) {row.add((int) ((long) row.get(i…...
NSOperation深入解析:从使用到底层原理
1. 基础概念与使用 1.1 NSOperation概述 NSOperation是Apple提供的一个面向对象的并发编程API,它基于GCD(Grand Central Dispatch)构建,但提供了更高层次的抽象和更丰富的功能。NSOperation允许开发者以面向对象的方式管理并发任…...
suna工具调用可视化界面实现原理分析(二)
这是一个基于React的浏览器操作可视化调试组件,主要用于在AI开发工具中展示网页自动化操作过程(如导航、点击、表单填写等)的执行状态和结果。以下是关键技术组件和功能亮点的解析: 一、核心功能模块 浏览器操作状态可视化 • 实时…...
【大模型面试每日一题】Day 9:BERT 的 MLM 和 GPT 的 Next Token Prediction 有什么区别?
【大模型面试每日一题】Day 9:BERT 的 MLM 和 GPT 的 Next Token Prediction 有什么区别? 📌 题目重现 🌟 面试官:预训练任务中,BERT 的 MLM(Masked Language Modeling)和 GPT 的 …...
分析strtol(),strtoul()和strtod()三个函数的功能
字符串转换为数值部分和子字符串首地址的函数有strtol(),strtoul()和strtod()三个函数。 1、strtol()函数 long int strtol(const char *str, char **endptr, int base) //当base0时,若字符串不是以"0","0x"和"0X"开头,则将数字部分按照10进制…...
Spring Boot 加载application.properties或application.yml配置文件的位置顺序。
我换一种更通俗易懂的方式,结合具体例子来解释 Spring Boot 加载application.properties或application.yml配置文件的位置顺序。 生活场景类比 想象你要找一本书,你有几个可能存放这本书的地方,你会按照一定顺序去这些地方找,直…...
C++进阶之——多态
1. 多态的概念 多态是用来描述这个世界的 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态。 这里就很厉害了,能够实现特殊处理,本文章就是来仔细…...
第13项三期,入组1123例:默沙东启动TROP2 ADC+PD-1子宫内膜癌头对头临床
Umabs DB作为目前全球最全面的抗体药物专业数据库,收录全球近10000个从临床前到商业化阶段抗体药物,涉及靶点1600,涉及疾病种类2400,研发机构2900,覆盖药物蛋白序列、专利和临床等多种专业信息。Umabs DB药物数据库已正…...
政务服务智能化改造方案和案例分析
政务服务智能化改造方案和案例分析 一、引言 在数字化时代浪潮的推动下,政务服务智能化改造已成为提升政府服务效能、优化营商环境、增强民众满意度的关键举措。传统政务服务模式存在流程繁琐、信息孤岛、办理效率低等问题,难以满足现代社会快节奏发展和…...
15.日志分析入门
日志分析入门 第一部分:日志分析基础第二部分:日志分析方法与工具第三部分:日志分析实践总结 目标: • 理解日志分析在网络安全中的作用 • 掌握日志的基本类型和分析方法 • 通过实践初步体验日志分析的过程 第一部分ÿ…...
EPSG:3857 和 EPSG:4326 的区别
EPSG:3857 和 EPSG:4326 是两种常用的空间参考系统,主要区别在于坐标表示方式和应用场景。以下是它们的核心差异: 1. 坐标系类型 EPSG:4326(WGS84) 地理坐标系(Geographic Coordinate System),基…...
Python Cookbook-7.2 使用 pickle 和 cPickle 模块序列化数据
任务 你想以某种可以接受的速度序列化和重建Python 数据结构,这些数据既包括基本Python 对象也包括类和实例。 解决方案 如果你不想假设你的数据完全由基本 Python 对象组成,或者需要在不同的 Python 版本之间移植,再或者需要将序列化后的…...
Java学习手册:Spring 多数据源配置与管理
在实际开发中,有时需要连接多个数据库,例如,一个系统可能需要从不同的数据库中读取和写入数据。Spring 提供了多种方式来配置和管理多数据源,以下将介绍常见的配置和管理方法。 一、多数据源配置 在 Spring 中,可以通…...
六、shell脚本--正则表达式:玩转文本匹配的“万能钥匙”
想象一下,你需要在一大堆文本(比如日志文件、配置文件、网页代码)里查找符合某种特定模式的字符串,而不是仅仅查找固定的单词。比如说: 找出所有的电子邮件地址 📧。找到所有看起来像电话号码 Ὅ…...
Gradio全解20——Streaming:流式传输的多媒体应用(4)——基于Groq的带自动语音检测功能的多模态Gradio应用
Gradio全解20——Streaming:流式传输的多媒体应用(4)——基于Groq的带自动语音检测功能的多模态Gradio应用 本篇摘要20. Streaming:流式传输的多媒体应用20.4 基于Groq的带自动语音检测功能的多模态Gradio应用20.4.1 组件及配置1.…...
力扣hot100 (除自身以外数组的乘积)
238. 除自身以外数组的乘积 中等 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除…...
LFU算法解析
文章目录 LFU缓存中关键变量的访问与更新机制1. min_freq - 最小频率访问时机更新时机更新示例 2. capacity - 缓存容量访问时机更新时机访问示例 3. key_to_node - 键到节点的映射访问时机更新时机更新示例 4. freq_to_dummy - 频率到链表哑节点的映射访问时机更新时机更新示例…...
RHCSA笔记2
RHCSA基础命令 (一)命令格式 (1)命令名【选项】【参数】 选项:决定命令执行的方式,通常有个-或--开头 参数:决定命令作用的目标(目录,文件,磁盘ÿ…...
JavaSE核心知识点01基础语法01-02(基本数据类型、运算符、运算符优先级)
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 JavaSE核心知识点01基础语法01-02࿰…...
FOC算法开环控制基础
1. 为什么要有FOC算法 先看看从有刷电机到无刷电机的简单介绍,如下图1,通电螺线圈会产生磁场,这个磁场会产生N级和S级,然后这个电磁铁就可以吸引永磁体,S级吸引N级,N级吸引S级,通俗的来说&…...
进程间通信——管道
概念 进程间通信(Inter-Process Communication,简称 IPC)是指在不同进程之间进行数据交换和信息传递的机制。它的目的主要有4种: 数据传输:一个进程需要将它的数据发送给另一个进程资源共享:多个进程之间…...
五一作业-day02
文章目录 1. 每日基操2. 模拟故障2.1 **remove regular empty file 是否删除普通文件(空的)?**2.2 **is a directory xxx是一个目录**2.3 **xxx not a directory 不是一个目录**2.4 Cant open file for writing2.5 **No write since last change** 3. 习题4. **进阶习题** 1. …...
Springclound常用五大组件及其使用原理
注册中心Eureka Eureka-Server:就是服务注册中心(可以是一个集群),对外暴露自己的地址。 提供者:启动后向Eureka注册自己信息(地址,服务名称等),并且定期进行服务续约 …...
Qt 显示QRegExp 和 QtXml 不存在问题
QRegExp 和 QtXml 问题 在Qt6 中 已被弃用; 1)QRegExp 已被弃用,改用 QRegularExpression Qt5 → Qt6 重大变更:QRegExp 被移到了 Qt5Compat 模块,默认不在 Qt6 核心模块中。 错误类型解决方法QRegExp 找不到改用 Q…...
开元类双端互动组件部署实战全流程教程(第4部分:后台配置系统与参数动态控制)
作者:曾经因为后台配置写错,导致全服进不去房的工程师 组件附带的后台管理系统为 PHP 编写,界面简洁但功能齐全。具备完整的模块划分与权限体系,支持动态参数下发、日志审计、行为数据统计等。 七、前端后台交互流程图与代码示例 …...
MySQL基础关键_008_DDL 和 DML(一)
目 录 一、DDL 1.创建表 (1)语法格式 (2)实例 2.查看建表语句 (1)语法格式 (2)实例 3.修改表名 (1)语法格式 (2)实例 4.新…...
基于SpringBoot + Vue 的火车票订票系统
包含: [1]源码✔ 数据库文件✔ [2]万字文档✔ [3]视频与图文配置教程✔ 功能描述: 本系统包含管理员、用户两个角色。 管理员:用户管理、新闻公告管理、车辆管理、车站及路线管理、留言建议管理、车次信息管理 用户:购票操作、查…...
飞致云开源社区月度动态报告(2025年4月)
自2023年6月起,中国领先的开源软件公司飞致云以月度为单位发布《飞致云开源社区月度动态报告》,旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况,以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源运营数据概览&…...
解决跨域的4种方法
00_跨域的概念 浏览器只允许请问具有相同的协议,域名,端口,进行请求,有一个不同,就会拒绝。 01.前后端协商jsonp //jsonp//jsonp 是 json with padding 的缩写,是一种通过 <script> 标签的 src 属性…...
C# 方法(局部函数和参数)
本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 局部函数 正如刚刚所解释的&…...
kotlin 02flow-sharedFlow 完整教程
一 sharedFlow是什么 SharedFlow 是 Kotlin 协程中 Flow 的一种 热流(Hot Flow),用于在多个订阅者之间 共享事件或数据流。它适合处理 一次性事件(如导航、弹窗、Toast、刷新通知等),而不是持续状态。 ✅ …...