h2database源码解析-如何更新一条行记录
这里的更新包括两种操作:删、改。更新操作涉及的内容在其他文章里面已经做过介绍了,本文主要是介绍更新的代码流程,以了解更新操作都做了哪些事情。如果有未介绍过的知识点会详细介绍。
目录
- 改(update)
- 如何判读是否加了行锁
- 删(delete)
改(update)
当执行update语句时,h2的执行流程如下:
- 根据查询条件制定执行计划,主要就是确认使用哪个索引,如果涉及多个表关联,确定表的关联顺序等;
- 对表加共享锁,对表加的共享锁都保存在lockSharedSessions属性中;
- 根据查询遍历所有的表记录,每遍历一条记录就加一个行锁,h2加行锁是在MVPrimaryIndex上加的,调用MVPrimaryIndex.lockRow()方法;
- 针对每行要修改的记录,重新构建一个新的行记录,新行记录里面的数据根据SQL语句要求为更新后的数据;
- 索引遍历从二级索引开始,调用索引的remove()方法将索引中要更新的记录,也就是B+树中的value更改为VersionedValueUncommitted对象,该对象里面保存了原索引的旧值以及更新后的行记录,二级索引更新完后,更新主键索引,更新主键索引的方式与二级索引一样,这一步只是将value做了替换,key没有变化;
- 从主键索引开始遍历,向索引中插入新的行记录数据,如果是更新B+树的value,那么将B+树中对应位置的value值替换为新的VersionedValueUncommitted对象,新对象里面包含了新行记录数据和旧行记录数据,如果SQL更新了索引中的字段值,那么向B+树中直接插入一个新的key和VersionedValueUncommitted对象的value。这样做的好处是当事务回滚或者事务未提交而结束事务,那么数据可以恢复到修改前的状态。注意此时索引里面只是插入了新key,旧key还记录在B+树里面;
- 事务提交,提交后将表和索引里面的VersionedValueUncommitted对象替换为事务已提交的对象,如果索引里面有旧key,则直接将key和value删除;
- 表解锁,也就是解除对表的共享锁。
行锁:h2加行锁其实是向表的B+树里面插入了一个value为VersionedValueUncommitted的对象,VersionedValueUncommitted里面保存了旧值。
VersionedValueUncommitted:从类名字上可以得到该对象与版本有关系,而且它还表示了事务未提交,该对象里面会保存两个数据,一个是事务id,另一个是undo log的id,每有一条记录被更改为VersionedValueUncommitted对象,那么便有一条对应的undo log。当两个事务同时操作同一个记录时,h2使用VersionedValueUncommitted来判断是否有其他事务已经对该记录加锁了。在本文后面详细介绍VersionedValueUncommitted以及如何判断是否加了行锁。
上面是执行update语句时,h2进行的操作。不知道大家注意没有,第5步和第6步修改数据都是直接在B+树中操作的,那么第7步更改B+树,h2是如何快速做到的,难道需要遍历整个B+树吗?h2能够快速完成第7步操作多亏了undo log,其实在第5步和第6步每进行一个操作都会记录一个undo log,事务提交的时候,直接对undo log回放就可以了。
如何判读是否加了行锁
在介绍h2如何判断一条记录是否已经加了行锁之前,先简单介绍下VersionedValueUncommitted类。
一个VersionedValueUncommitted对象表示B+树上的一个value,对于主键索引来说,这个对象里面存储的就是行记录,不过这个对象有点特殊,它存储的数据表示事务还未提交,当事务提交后,这个对象就会被清理掉。VersionedValueUncommitted继承自VersionedValueCommitted,综合VersionedValueUncommitted的父类及祖先类可以看到,VersionedValueUncommitted一共只有三个属性:
public final T value;//存储更新后的值private final long operationId;//该值有两部分组成,后40 bit表示undo log id,其他bit表示的就是事务id,也就是正在更新数据的事务idprivate final T committedValue;//存储更新前的值
当h2想对某条记录加锁时,首先访问索引MVPrimaryIndex,根据key找到value,如果已经有其他事务对该记录加了锁,那么当前事务拿到的value便是VersionedValueUncommitted对象,那么h2便可以从VersionedValueUncommitted对象里面得知,当前是否有其他事务加锁,以及加锁的事务id是多少,下面代码是h2拿到VersionedValueUncommitted对象后进行的判断:
//existingValue是VersionedValueUncommitted对象的committedValue属性值//existingValue.getOperationId()得到的就是事务id//isThisTransaction()方法判断当前事务是否与已经对行加锁的事务相同if (existingValue == null ||// or entry is a committed one(id = existingValue.getOperationId()) == 0 ||// or it came from the same transactionisThisTransaction(blockingId = TransactionStore.getTransactionId(id)))
如果上面的代码判断为false,表示已经有其他事务加了锁,而且事务还没提交,接下来调用toWaitFor.waitForThisToEnd()方法等待一段时间,如果在等待期间解锁了,那么当前事务重新对行加锁,否则抛出所等待超时的异常,默认等待时间为2s。
删(delete)
delete操作相对update操作来说,其执行流程的前三步是一样的,都需要先指定执行计划、查出数据、加锁,下面直接介绍与update不同的地方。
- 遍历每个索引,从二级索引开始遍历最后遍历主键索引,调用每个索引的index.remove()方法,与update操作的第五步不同的是,这里的VersionedValueUncommitted对象的value属性是null;
- 事务提交,将各个索引里面的涉及到删除的记录全部删除;
- 表解锁,也就是解除对表的共享锁。
delete操作可以看做是update操作的子集。
相关文章:
h2database源码解析-如何更新一条行记录
这里的更新包括两种操作:删、改。更新操作涉及的内容在其他文章里面已经做过介绍了,本文主要是介绍更新的代码流程,以了解更新操作都做了哪些事情。如果有未介绍过的知识点会详细介绍。 目录改(update)如何判读是否加了行锁删(delete)改(upda…...

FyListen——生命周期监听器(设计原理之理解生命周期)
FyListen——生命周期监听器(设计原理之理解生命周期) FyListen 的核心原理有两个: 通过子Fragment对Activity、Fragment进行生命周期监听Java8 接口特性 default 1. 什么是上下文Context 这是一个装饰器模式, ContextImpl 是 …...

Element UI框架学习篇(六)
Element UI框架学习篇(六) 1 删除数据 1.1 前台核心函数 1.1.1 elementUI中的消息提示框语法 //①其中type类型和el-button中的type类型是一致的,有info灰色,success绿色,danger红色,warning黄色,primary蓝色 //②message是你所要填写的提示信息 //③建议都用,因为比双引号…...

Python如何安装模块,python模块安装失败的原因以及解决办法
前言 今天来给刚开始学习python的朋友讲解一下 如何安装python模块, python模块安装失败的原因以及解决办法 很多朋友拿到代码之后,就开始复制粘贴 --> 然后右键进行运行 结果就是报错说 没有这个模块 得安装啥的 Python模块安装 一. 打开命令提示符 win …...
《NFL橄榄球》:洛杉矶闪电·橄榄1号位
洛杉矶闪电(英语:Los Angeles Chargers),又译“洛杉磯衝鋒者”。是一支位于加利福尼亚州洛杉矶郡英格尔伍德的职业美式橄榄球球队,现为美国橄榄球联合会西区成员之一。该队曾于1961年搬迁到圣地亚哥而改叫圣地亚哥电光…...
4.7 Python设置代码格式
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。请花时让你的代码尽可能易于阅读;让代码易于阅读有助于你掌握程序是做什么的,也可以帮助他人理解你编写的代码。为确保所有人编写的代码的结构都大致一致,Python程序员都遵循一些格…...

Zabbix 构建监控告警平台(五)
Zabbix 自动发现Zabbix 自动注册1.Zabbix 自动发现 1.1前言 为了满足监控企业成千上万台服务器,因此我们需要使用Zabbix批量监控来实现。自动发现和自动注册。 1.2zabbix-server (一)1、创建自动发现规则 在“配置”->“自动发现”->“…...

2023关键词:挑战
未失踪人口回归… 好久不见,不经意间拖更2个多月。今天周末,外面淅淅沥沥下着小雨,这种窝在床上的时刻最适合写点东西了。 但是建议大家在办公或者写博客的时候尽量还是端正坐姿,我就是因为喜欢这样靠在床背上,长时间…...
Wifi wpa_supplicant 到驱动的联系
同学,别退出呀,我可是全网最牛逼的 WIFI/BT/GPS/NFC分析博主,我写了上百篇文章,请点击下面了解本专栏,进入本博主主页看看再走呗,一定不会让你后悔的,记得一定要去看主页置顶文章哦。 从framework到wpa_supplicant的适配层,其中framework部分需要了注意的是wifiservic…...

【状态估计】基于二进制粒子群优化 (BPSO) 求解最佳 PMU优化配置研究【IEEE30、39、57、118节点】(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
python 将 .pdf 文件转为 .md
环境准备 pip install aspose-words 代码 doc aw.Document(r"pdf 文件路径\xxx.pdf") doc.save("Output.md") 来源:https://products.aspose.com/words/zh/python-net/conversion/...

【C语言】操作符详解
每天一篇博客,卷死各位。 文章目录前言1. 算术操作符2. 移位进制位的表示移位操作符1. 》--左移操作符2. 《--右移操作符3.位操作符4.赋值操作符5.单目操作符6.关系操作符7. 逻辑操作符8.条件操作符9.逗号操作符总结前言 在c语言学习中操作符尤为重要,而…...

微信小程序 学生选课系统--nodejs+vue
系统分为学生和管理员,教师三个角色 学生小程序端的主要功能有: 1.用户注册和登陆系统 2.查看选课介绍信息 3.查看查看课程分类 4.查看课程详情,在线选课,提交选课信息 5.在线搜索课程信息 6.用户个人中心修改个人资料 7.用户查看…...

leaflet 加载geojson文件并显示图形(示例代码051)
第051个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载geojson文件,将图形显示在地图上。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果OpenStreetMap无法加载,请加载其他来练习 文章目录 示例效果配置方式示例源代码(…...
【Kafka】ZK和Kafka集群的安装和配置
一、集群环境说明1. 虚拟机:192.168.223.101/103/1052. 系统版本:CentOS 7.93. JDK版本:11.0.18.0.14. Zookeeper版本:3.7.15. Kafka版本:2.13-2.8.2备注:无论是ZK,还是Kafka,都需要…...
并发编程出现的问题以及解决方式
解决并发编程出现的问题基于java内存模式的设计出现的问题基于java内存模式的设计,多线程操作一些共享的数据时,出现以下三个问题:1.不可见性问题:多个线程同时在各自的工作内存对共享数据进行操作,彼此之间不可见。操…...
[ linux ] linux 命令英文全称及解释
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】🎉点赞➕评论➕收藏 养成习…...

C++11新特性
文章目录说在前面花括号{}初始化new的列表初始化STL相关容器的列表初始化相关语法格式容器列表初始化的底层原理forward_list和array与类型相关的新特性decltype左值引用和右值引用什么是左值,什么是右值左值和右值的本质区别右值引用如何理解右值引用std::move移动…...

【宝塔部署SpringBoot前后端不分离项目】含域名访问部署、数据库、反向代理、Nginx等配置
一定要弄懂项目部署的方方面面。当服务器上部署的项目过多时,端口号什么时候该放行、什么时候才会发生冲突?多个项目使用redis怎么防止覆盖?Nginx的配置会不会产生站点冲突?二级域名如何合理配置?空闲的时候要自己用服…...

从0到1一步一步玩转openEuler--11 openEuler基础配置-设置磁盘调度算法
11 openEuler基础配置-设置磁盘调度算法 文章目录11 openEuler基础配置-设置磁盘调度算法11.1 设置磁盘调度算法11.1.1 临时修改调度策略11.1.2 永久设置调度策略11.1 设置磁盘调度算法 本节介绍如何设置磁盘调度算法。 11.1.1 临时修改调度策略 例如将所有IO调度算法修改为…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space
问题:IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案:将编译的堆内存增加一点 位置:设置setting-》构建菜单build-》编译器Complier...
计算机系统结构复习-名词解释2
1.定向:在某条指令产生计算结果之前,其他指令并不真正立即需要该计算结果,如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方,那么就可以避免停顿。 2.多级存储层次:由若干个采用不同实现技术的存储…...

MCP和Function Calling
MCP MCP(Model Context Protocol,模型上下文协议) ,2024年11月底,由 Anthropic 推出的一种开放标准,旨在统一大模型与外部数据源和工具之间的通信协议。MCP 的主要目的在于解决当前 AI 模型因数据孤岛限制而…...