Insight h2database 更新、读写锁以及事务原理
文章基于 RegularTable 来分析和拆解更新操作。
锁模型比较简单,方便了解更新的整个流程。并发读写的实现在 MVStore 存储引擎中分析。
主要关注数据更新的实现、事务的提交和回滚。
相关概念
讨论更新操作,就需要涉及到事务隔离级别以及事务的概念。
也就是讨论如何控制并发读写的问题、以及undolog 的问题。
①MVCC
multi version concurrency。在 h2database 实现中,只有 MVStore 存储引擎支持该特性。MVCC 实现原理参考《Insight h2database MVCC 实现原理》。
/*** Check if multi version concurrency is enabled for this database.* @see org.h2.engine.Database#isMultiVersion*/
public boolean isMultiVersion() {// this.multiVersion = ci.getProperty("MVCC", dbSettings.mvStore);return multiVersion;
}/*** 通过设置或者版本确定是否启用 MVStore 存储引擎* @see org.h2.engine.DbSettings#mvStore*/
public boolean mvStore = get("MV_STORE", Constants.VERSION_MINOR >= 4);
②事务隔离级别
the isolation level. 在 h2database 中,通过 LOCK_MODE 体现。不同的锁定模式决定了事务级别。参考命令 SET LOCK_MODE int。
-
SET LOCK_MODE 命令是数据库级别的,影响全局(affects all connections)。
-
默认的事务隔离级别为 READ_COMMITTED。但只限在 MVStore 存储引擎中。
-
对于 RegularTable 只存在两种级别:READ_UNCOMMITTED, SERIALIZABLE。
-
READ_UNCOMMITTED,即无锁定模式(仅用于测试)
-
SERIALIZABLE,不同事务(session)读写互斥。可以防止脏读、不可重复读和幻读,但是效率较低,因为它会锁定所涉及的全部表,直到整个事务完成。
RegularTable 表级独占锁
更新流程中,首先会调用 table.lock(session, exclusive = true, false);
在 RegularTable 中,表会按照 session 粒度控制并发度。这个方法只能当前 session 可重入,其他 session 想 lock 成功,需要等待当前会话释放锁。
①独占锁示例
-- session 1 更新数据并持有锁
SET AUTOCOMMIT OFF;
update city set code = 'bjx' where id = 9;-- session 2 获取锁超时,异常
select * from city where id = 5;Timeout trying to lock table "CITY"; SQL statement:
select * from city where id = 5 [50200-184] HYT00/50200
②独占锁实现
Java 经典的多线程同步示例。同时包含了死锁检测的实现方案。
/*** 通过会话,给表加锁。* 如果要加写锁,会存在等待锁的情况。* 如果发生锁超时,将抛出DbException异常。如上示例。* @param session 当前会话* @param exclusive 如果为true,表示需要写锁;如果为false,表示需要读锁。写锁是排他的,即在同一时间只能有一个线程持有写锁。读锁是共享的,即在同一时间可以有多个线程持有读锁。* @see org.h2.table.RegularTable#lock*/
public boolean lock(Session session, boolean exclusive, boolean forceLockEvenInMvcc) {int lockMode = database.getLockMode();// 无锁模式,直接返回。 if (lockMode == Constants.LOCK_MODE_OFF) {// 返回是否存在独占 session, 没有使用到,约等于无,不用关注。return lockExclusiveSession != null;}// 如果是当前 session 独占,相当于锁重入(如果一个会话已经持有了这个表的独占锁,那么它可以再次获取这个锁,而不会被自己阻塞。)if (lockExclusiveSession == session) {return true;}synchronized (database) {// double check 😁if (lockExclusiveSession == session) {return true;}// 读锁,共享,直接返回。if (!exclusive && lockSharedSessions.contains(session)) {return true;}// 写锁,进入等待队列session.setWaitForLock(this, Thread.currentThread());waitingSessions.addLast(session);try {// while 循环出队列加锁 or 等待加锁。// 真正的加锁在 doLock2 方法中。根据读写锁不同(exclusive), 执行不同的操作。doLock1(session, lockMode, exclusive);} finally {session.setWaitForLock(null, null);waitingSessions.remove(session);}}return false;
}
RegularTable 更新流程
了解独占锁的工作机制后,对于数据更新事务的原子性、一致性、隔离级别就没有疑问了。以下主要列出数据更新的主流程,比如查找并更新,触发器时机。
/*** 执行数据更新* @see org.h2.command.dml.Update#update*/
public int update() {// 记录哪些数据需要更新。RowList rows = new RowList(session);try {Table table = tableFilter.getTable();session.getUser().checkRight(table, Right.UPDATE);// 尝试添加写锁(独占锁)table.lock(session, true, false);// 查询需要更新的数据, select by conditionwhile (tableFilter.next()) {if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) {// 旧数据,直接查出来的。Row oldRow = tableFilter.get();// 新数据,根据更新语句,重新赋值后的。Row newRow = table.getTemplateRow();// 执行 set column 表达式...boolean done = false;if (table.fireRow()) {// 数据变更前,分发执行触发器。触发器太多可不行❌done = table.fireBeforeRow(session, oldRow, newRow);}if (!done) {rows.add(oldRow);rows.add(newRow);}}}// 存储引擎执行真正的数据更新操作。⛳table.updateRows(this, session, rows);if (table.fireRow()) {for (rows.reset(); rows.hasNext();) {// 数据变更后,分发执行触发器table.fireAfterRow(session, o, n, false);}}return count;} finally {rows.close();}
}
事务控制
因为 RegularTable 存储引擎事务是 SERIALIZABLE 级别。就不存在读写并发的情况。事务的提交不做过多分析,主要关注事务回滚的实现。
①AutoCommit
和其他数据库一样, h2database 会话默认的 AutoCommit = true。更新命令执行完成会自动发起 commit 操作。
开启事务的情况下,由用户手动发起 commit 操作。
/*** 更新命令执行完成后,收尾工作之一判断是否需要发起自动提交✔* @see org.h2.command.Command#stop*/
private void stop() {// AutoCommit 状态,自动提交事务。if (session.getAutoCommit()) {session.commit(false);}
}
②事务提交
org.h2.command.dml.TransactionCommand#update 命令处理
/*** Commit the current transaction. ** @see org.h2.engine.Session#commit*/
public void commit(boolean ddl) {// 事务持久化机制,及时存盘数据库操作记录。if (containsUncommitted()) {database.commit(this);}if (undoLog.size() > 0) {undoLog.clear();}// 释放当前会话关联 table 的读写锁。// @see org.h2.engine.Session#unlockAllendTransaction();
}
③事务回滚
org.h2.command.dml.TransactionCommand#update 命令处理
事务的回滚依赖 undoLog。实现类:org.h2.engine.UndoLogRecord,undoLog 只存在两种操作 INSERT DELETE。对应到 SQL 操作:
-
Insert SQL: INSERT new, 回滚操作为:DELETE new
-
Update SQL: DELETE old, INSERT new, 回滚操作为:DELETE new, INSERT old
-
Delete SQL: DELETE old, 回滚操作为:INSERT old
/*** 事务回滚操作。* 事务回滚的过程就是按照逆序回放事务中的操作(undoLog中的操作逆序执行)。** @param savepoint 如果指定保存点,事务将回滚到这个保存点。* @param trimToSize if the list should be trimmed*/
public void rollbackTo(Savepoint savepoint, boolean trimToSize) {// 保存点持有的是当前会话开始时 undoLog 的位置。默认都是 0。int index = savepoint == null ? 0 : savepoint.logIndex;// 当前会话 undoLog 队列逆向回放,重置现场。while (undoLog.size() > index) {UndoLogRecord entry = undoLog.getLast();// 如上的对应操作规则,回放操作。entry.undo(this);undoLog.removeLast(trimToSize);}
}
相关文章:
Insight h2database 更新、读写锁以及事务原理
文章基于 RegularTable 来分析和拆解更新操作。 锁模型比较简单,方便了解更新的整个流程。并发读写的实现在 MVStore 存储引擎中分析。 主要关注数据更新的实现、事务的提交和回滚。 相关概念 讨论更新操作,就需要涉及到事务隔离级别以及事务的概念。 也…...

skywalking动态配置[集成nacos/apollo/consul]
说明:以下配置仅关于的阈值规则的动态配置,其他参数也可以进行配置。 1,skywalking动态配置集成nacos 编辑application.yml nacos配置参数如下: nacos:# Nacos Server HostserverAddr: 10.10.5.145# Nacos Server Portport: 8848# Nacos Configuration Groupgroup: skywal…...

UniApp创建项目HelloWorld
浏览器预览效果镇楼 普通项目创建 点击创建完成后,就如下所示 确实和微信小程序开发差不多。只是稍微换了一个名字的概念了,这个就是开发嘛,不要过于纠结概念性东西。开发开发,开了就知道怎么发了? 或许是 反正write就…...

Qt/C++原创推流工具/支持多种流媒体服务/ZLMediaKit/srs/mediamtx等
一、前言 1.1 功能特点 支持各种本地视频文件和网络视频文件。支持各种网络视频流,网络摄像头,协议包括rtsp、rtmp、http。支持将本地摄像头设备推流,可指定分辨率和帧率等。支持将本地桌面推流,可指定屏幕区域和帧率等。自动启…...
学习黑马程序员JavaScript总结
今天注意学习了数据类型、运算符、常量、数组,这些内容接受的还是比较快的,因为前面学过C语言还有Python,比较不同的地方就是未定义类型undefined,这个类型是在只声明了变量但未赋值,而unll空类型它是赋了值但该值是空…...

浅谈高速公路服务区分布式光伏并网发电
前言 今年的国家经济工作会议提出:将“做好碳达峰、碳中和工作”作为 2021年的主要任务之一,而我国高速公路里程 15.5万公里,对能源的需求与日俱增,碳排放量增速明显。 为了实现采用减少碳排放量,采用清洁能源替代的…...
MATLAB算法实战应用案例精讲-【图像处理】机器视觉(番外篇)
目录 前言 算法原理 机器视觉检测系统工作原理 机器视觉光源分类...

塑胶材料检测对激光焊机的作用
塑胶材料的激光焊接已经普遍用于各种零配件,而塑料的透光率是焊接工艺质量的一个重要指标。针对这类塑胶材料推出这款专门检测塑胶材料近红外透光率特性的透光率检测仪,对注塑件的透光率进行全画面扫描。 全球工业致力于贯彻绿色环保、节能减排发展理念&…...
将Eureka服务注册到Eureka中心
1、在微服务的pom.xml引入依赖文件中 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>2、在微服务的application.yml配置文件中加上…...

将网站域名访问从http升级到https(腾讯云/阿里云)
文章目录 1.前提说明2.服务器安装 docker 与 nginx2.1 安装 docker🍀 基于 centos 的安装🍀 基于ubuntu 2.2 配置阿里云国内加速器🍀 找到相应页面🍀 创建 docker 目录🍀 创建 daemon.json 文件🍀 重新加载…...

QT通过TCP协议发送结构体数据
QT通过TCP协议发送结构体数据 Chapter1 QT通过TCP协议发送结构体数据前言1. memcpy方式1.1 发送整个结构体1.2 发送部分数据 2. QDataStream2.1 符号<<2.2 wrieteRawData 总结 Chapter2 qt中操作json,读取json,写入json,转换json一、说…...
C++标准库之numeric
文章目录 一. numeric库介绍二.详解accumulate1. 计算数组中所有元素的和2. 计算数组中所有元素的乘积3. 计算数组中每个元素乘以3之后的和4.计算数组中每个元素减去3之后的和5.计算班级内学生的平均分6.拼接字符串 adjacent_differenceinner_productpartial_sumiota 三. 参考 …...
第六章:最新版零基础学习 PYTHON 教程—Python 正则表达式(第二节 - Python 中的正则表达式与示例套装)
正则表达式 (RegEx)是一种特殊的字符序列,它使用搜索模式来查找字符串或字符串集。它可以通过将文本与特定模式进行匹配来检测文本是否存在,并且还可以将模式拆分为一个或多个子模式。Python 提供了一个re模块,支持在 Python 中使用正则表达式。它的主要功能是提供搜索,其中…...

【Python】WebUI自动化—Selenium的下载和安装、基本用法、项目实战(16)
文章目录 一.介绍二.下载安装selenium三.安装浏览器驱动四.QuickStart—自动访问百度五.Selenium基本用法1.定位节点1.1.单个元素定位1.2.多个元素定位 2.控制浏览器2.1.设置浏览器窗口大小、位置2.2.浏览器前进、刷新、后退、关闭3.3.等待3.4.Frame3.5.多窗口3.6.元素定位不到…...

c++视觉处理---图像重映射
图像重映射:cv::remap cv::remap 是OpenCV中的一个函数,用于执行图像重映射,允许您通过重新映射像素的位置来变换图像。这个函数非常有用,可以用于各种图像处理任务,如校正畸变、透视变换、几何变换等。 下面是 cv::…...

基于YOLO算法的单目相机2D测量(工件尺寸和物体尺寸)
1.简介 1.1 2D测量技术 基于单目相机的2D测量技术在许多领域中具有重要的背景和意义。 工业制造:在工业制造过程中,精确测量是确保产品质量和一致性的关键。基于单目相机的2D测量技术可以用于检测和测量零件尺寸、位置、形状等参数,进而实…...
Insight h2database 执行计划评估以及 Selectivity
生成执行计划是任何一个数据库不可缺少的过程。通过本文看执行计划生成原理。 最优的执行计划就是寻找最小计算成本的过程。 本文侧重 BTree 索引的成本计算的实现 以及 基础概念选择度的分析。 寻找最优执行计划 找到最佳的索引,实现最少的遍历,得到想要…...

[天翼杯 2021]esay_eval - RCE(disabled_function绕过||AS_Redis绕过)+反序列化(大小写wakeup绕过)
[天翼杯 2021]esay_eval 1 解题流程1.1 分析1.2 解题1.2.1 一阶段1.2.2 二阶段二、思考总结题目代码: <?php class A{public $code = "";...

基于SSM+Vue的在线作业管理系统的设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用Vue技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...

Webapck 解决:[webpack-cli] Error: Cannot find module ‘vue-loader/lib/plugin‘ 的问题
1、问题描述: 其一、报错为: [webpack-cli] Error: Cannot find module vue-loader/lib/plugin 中文为: [webpack-cli] 错误:找不到模块“vue-loader/lib/plugin” 其二、问题描述为: 在项目打包的时候 npm run …...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...