H2数据库中一条insert语句到生成java对象到数据写入磁盘的完整步骤

H2 数据库将 SQL 语句转换为磁盘存储的全过程可以分为以下 8 个关键步骤,我们以 INSERT INTO users (id, name) VALUES (1, 'Alice') 为例详细说明:


1. SQL 解析与语法树生成

  • 词法分析:拆分语句为 INSERTINTOusers 等 Token
  • 语法分析:构建抽象语法树(AST),验证表结构是否存在
  • 语义分析:确认 idname 字段类型匹配

2. 事务管理与日志写入(WAL)

– 隐式事务开始
INSERT INTO users VALUES (1, ‘Alice’);
– COMMIT 触发日志落盘

  • 预写日志:先将操作记录写入 .trace.db 文件

  • 日志格式

    INSERT INTO PUBLIC.USERS(ID, NAME) VALUES (1, ‘Alice’)


3. 内存数据结构操作

  • MVStore 引擎(默认):
    • 将数据暂存内存中的 B+Tree 结构

    • Key-Value 存储格式:

      {
      “key”: 1,
      “value”: {
      “id”: 1,
      “name”: “Alice”
      }
      }


4. 页式存储管理(PageStore)


5. 索引维护

  • 主键索引:自动创建 PRIMARY_KEY_INDEX

    // B+Tree 结构示例
    BPlusTree index = new BPlusTree();
    index.put(1, new PagePointer(0x01, 128)); // 指向页0x01的128字节偏移


6. 检查点(Checkpoint)触发

  • 触发条件
    • 事务提交时设置 FORCE_WRITE=true
    • 内存中脏页比例超过阈值(默认 50%)
  • 持久化过程
    1. 暂停新事务
    2. 将内存中的 B+Tree 序列化为二进制格式
    3. 追加写入 .h2.db 文件

7. 物理存储结构

数据库文件结构

users.h2.db # 主数据文件
users.temp.db # 临时文件(合并操作时使用)
users.lock.db # 文件锁控制
users.trace.db # WAL 日志文件


8. 崩溃恢复机制

当异常关闭后重启时:

  1. 检查 .trace.db 日志文件
  2. 回放未提交的事务(Rollback)
  3. 验证 .h2.db 文件的 checksum
  4. 重建内存中的 B+Tree 索引

技术亮点

  1. MVCC 实现:通过 TRANSACTION_ID 字段实现多版本控制
  2. 压缩优化:使用 LZF 算法压缩数据页(默认关闭)
  3. 加密支持:可选 AES-128 加密整个数据文件

通过这种分层处理机制,H2 既保证了 ACID 特性,又能达到 50,000+ TPS 的写入性能(内存模式)。实际存储格式会根据 MVStorePageStore 引擎的选择有所不同,以上流程以 MVStore 为主。


**user**: 

重新生成一遍,sql ,解析成java 对象,用了什么数据结构,索引,如何存储到磁盘的


**assistant**: 

以下是 H2 数据库将 SQL 语句转换为 Java 对象并最终存储到磁盘的完整技术过程,结合 INSERT INTO users (id, name) VALUES (1, 'Alice') 示例:


1. **SQL 解析与 Java 对象生成

解析过程

// 使用 H2 的解析器生成 Command 对象
Parser parser = new Parser(connection);
String sql = “INSERT INTO users (id, name) VALUES (1, ‘Alice’)”;
Command command = parser.parseCommand(sql); // 返回 Insert 对象

// Insert 对象结构 (org.h2.command.dml.Insert)
class Insert {
Table table; // users 表的元数据
Column[] columns; // [id, name]
Expression[] values; // [1, ‘Alice’]
int rowId; // 内存中的临时行号
}

关键数据结构

// 内存中的行数据表示 (org.h2.result.Row)
Row row = table.getTemplateRow();
row.setValue(0, ValueInt.get(1)); // id 列
row.setValue(1, ValueString.get(“Alice”)); // name 列

// 值对象的内存结构 (org.h2.value.Value)
class ValueInt {
int value;
byte[] memoryBytes; // 序列化后的字节缓存(用于快速存储)
}


2. **内存数据结构与索引

表数据存储(MVStore 引擎)

// MVStore 的 B+Tree 实现 (org.h2.mvstore.MVMap)
MVMap<Integer, Row> tableMap = store.openMap(“users”);

// 插入数据到内存树
tableMap.put(1, row); // key=id, value=Row对象

// Row 的内存结构
class Row {
Value[] data; // [1, “Alice”]
long version; // MVCC 版本号
int transactionId; // 关联的事务ID
}

索引结构(B+Tree 实现)

// 主键索引 (org.h2.index.PageBtreeIndex)
PageBtreeIndex primaryIndex = new PageBtreeIndex(…);

// 索引节点结构
class BTreeNode {
Object[] keys; // [1]
long[] children; // 子节点页号(内存地址或磁盘页ID)
boolean isLeaf;
}

// 索引条目
class IndexEntry {
int key; // id=1
PagePointer pointer;// 指向数据页的位置 (pageId=0x01, offset=128)
}


3. **磁盘存储细节

MVStore 文件格式(默认引擎)

数据文件 users.mv.db 的二进制结构

[File Header] [Chunk 1] [Chunk 2] … [Chunk N]

Chunk 结构示例

Chunk {
int chunkId; // 递增的块ID
long blockCount; // 占用的块数
byte[] mapData; // 序列化的 MVMap 数据
byte[] btreeNodes; // B+Tree 节点二进制数据
}

单行存储的二进制格式

// Row 的序列化过程
ByteBuffer buf = ByteBuffer.allocate(128);
DataUtils.writeVarInt(buf, 1); // id
DataUtils.writeString(buf, “Alice”); // name
byte[] rowBytes = buf.array(); // 最终字节数组

// 磁盘存储示例(十六进制):
01 00 00 00 // id=1 (4字节)
41 6C 69 63 65 // “Alice” (UTF-8 bytes)

页式存储(PageStore 引擎)

// 数据页结构 (org.h2.store.Page)
class Page {
int pageId; // 0x01
byte[] data; // 页内容(包含多行数据)
int type; // 页类型(数据页/索引页)
}

// 页内数据组织
DataPage {
Row[] rows; // 行数据数组
int freeSpace; // 剩余空间计数
int nextPage; // 下一页指针
}


4. **持久化触发机制

事务提交时的写入

// 事务提交操作 (org.h2.engine.Session)
session.commit();

// 持久化步骤:

  1. 将 MVStore 的脏页标记为待写入
  2. 通过 FileStore.write() 异步写入磁盘
  3. 更新文件头部的元数据块

// 关键写入类
FileStore fileStore = new FileStore();
fileStore.write(ByteBuffer data, long position); // 直接操作文件通道

检查点(Checkpoint)示例

// 检查点线程 (org.h2.engine.CheckpointThread)
public void run() {
if (needCheckpoint()) {
store.sync(); // 强制同步内存数据到磁盘
}
}

// 触发条件:
// - 超过 checkpointInterval (默认 30秒)
// - 日志文件超过 16MB


5. **技术关键点

  1. 内存与磁盘的桥梁

    • Row 对象同时存在于内存(Java Heap)和堆外内存(DirectByteBuffer)
    • 通过 Value#getBytes() 实现快速序列化
  2. 索引加速

    // 索引查询示例
    Cursor cursor = primaryIndex.find(1); // 二分查找 B+Tree
    Page page = readPage(cursor.getPageId());
    Row row = page.getRow(cursor.getOffset());

  3. 压缩与加密

    // 文件存储配置
    MVStore.Builder()
    .compress() // 启用 LZF 压缩
    .encryptionKey(“AES”, “password”.toCharArray());


完整流程示例

  1. 用户发送 INSERT SQL
  2. 生成 Insert 命令对象
  3. 创建 Row 并填充 Value 数据
  4. 更新内存中的 MVMap(B+Tree)
  5. 事务提交时触发:
    • 写入 WAL 日志(.trace.db
    • 标记脏页
    • 异步线程执行磁盘写入
  6. 数据最终以分块形式持久化到 .mv.db 文件

通过这种设计,H2 在保证 ACID 的同时,内存模式可达 50,000 TPS,持久化模式性能约为 8,000 TPS(取决于磁盘速度)。开发者可通过 MVStore API 直接操作底层存储结构。

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

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

相关文章

重磅升级!Google Play商店改版上线

5 月 21 日消息&#xff0c;Android Headline 今天&#xff08;5 月 21 日&#xff09;发布博文&#xff0c;报道称在 2025 年 I/O 开发者大会上&#xff0c;谷歌宣布更新 Google Play 应用商店&#xff0c;在优化用户体验的同时&#xff0c;提升开发者收益。 本次更新中&…

Docker面试题(1)

什么是Docker 一个容器化平台 形式是容器 将你的应用程序及所有依赖项打包在一起 确保应用程序在任何环境中无缝运行 什么是Docker镜像 Docker镜像是Docker容器的源代码 用于创建容器 使用build命令创建镜像 什么是 Docker容器 包括应用程序及所有的依赖项 作为操作系统的独立进…

Ulisses Braga-Neto《模式识别和机器学习基础》

模式识别和机器学习基础 [专著] Fundamentals of pattern recognition and machine learning / (美)乌利塞斯布拉加&#xff0d;内托(Ulisses Braga-Neto)著 ; 潘巍[等]译 推荐这本书&#xff0c;作者有自己的见解&#xff0c;而且提供代码。问题是难度高&#xff0c;对于初学…

RabbitMQ的简介

三个概念 生产者&#xff1a;生产消息的服务消息代理&#xff1a;消息中间件&#xff0c;如RabbitMQ消费者&#xff1a;获取使用消息的服务 消息队列到达消费者的两种形式 队列&#xff08;queue&#xff09;:点对点消息通信&#xff08;point-to-point&#xff09; 消息进入队…

自动切换剪贴板路径中反斜杠为正斜杠

有时候需要将我们常见的win全路径中反斜杠为正斜杠&#xff0c;每次用记事本&#xff0c;编辑替换非常麻烦&#xff0c;于是写了这个工具&#xff0c;能自动修改剪贴板中的数据&#xff0c;只需要运行一下即可。 实现效果&#xff0c;将类似于下面的路径&#xff1a; C:\User…

【时时三省】Python 语言----文件

目录 1,文件打开 2, 文件关闭 3, 文件写入 4, 文件读出 5, 文件定位 6, 文件重命名 7, 复制文件 山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 1,文件打开 file = open(file, mode, buffering, encoding, errors, newline, closefd, opener) 2, 文…

React 个人笔记 Hooks编程

作用 配合函数式编程&#xff0c;保证在不产生类的时候完成一个整体的组件 常用组件 useStateuseContextuseReduceruseEffectuseMemouseCallback 前三个值为自变量 后三者为因变量 前三者相当于其他编程函数的变量声明&#xff0c;而后三者相当于对变量进行了(if now ! pr…

logits是啥、傅里叶变换

什么是logtis&#xff1f; 在深度学习的上下文中&#xff0c;logits 就是一个向量&#xff0c;下一步通常被投给 softmax/sigmoid 的向量。。 softmax的输出是分类任务的概率&#xff0c;其输入是logits层。 logits层通常产生-infinity到 infinity的值&#xff0c;而softmax层…

Adobe Illustrator学习备忘

1.移动画板&#xff1a;需按住空格键加鼠标一块才能拖动 2.放大缩小画板&#xff1a;按住Alt键加鼠标滚轮 3.撤回&#xff1a;CtrlZ 4.钢笔练习网站&#xff1a;The Bzier Game

【初识】内网渗透——基础概念,基本工具使用

目录 一、域&#xff0c;工作组&#xff0c;域控制器&#xff0c;活动目录相关概念&#xff1a; 域环境&#xff1a; 工作组&#xff1a; 域控制器DC&#xff1a; 活动目录AD&#xff1a; 二、内网的基本场景&#xff1a; 三、内网渗透基本测试方案&#xff1a; #案例1一基本信…

remove_const的工作原理及c++的类型推导

author: hjjdebug date: 2025年 05月 21日 星期三 12:51:57 CST descrip: remove_const的工作原理及c的类型推导 文章目录 1. 简单的程序代码.2.std::remove_const_t 到底是怎样工作的&#xff1f;2.1 测试代码2.2 类型推导的调试手段.2.2.1 给类模板添加成员函数,让它打印信息…

人脸识别,使用 deepface + api + flask, 改写 + 调试

1. 起因&#xff0c; 目的&#xff0c; 感受: github deepface 这个项目写的很好&#xff0c; 继续研究使用这个项目&#xff0c;改写 api。增加一个前端 flask app 2. 先看效果 3. 过程: 大力改写原始项目中 api 这部分的代码&#xff0c; 原始项目的文件结构太繁杂了: 我把…

三维表面轮廓仪的维护保养是确保其长期稳定运行的关键

三维表面轮廓仪是一种高精度测量设备&#xff0c;用于非接触式或接触式测量物体表面的三维形貌、粗糙度、台阶高度、纹理特征等参数。其主要基于光学原理进行测量。它利用激光或其他光源投射到被测物体表面&#xff0c;通过接收反射光或散射光&#xff0c;结合计算机图像处理技…

Lambda表达式的高级用法

今天来分享下Java的Lambda表达式&#xff0c;以及它的高级用法。 使用它可以提高代码的简洁度&#xff0c;使代码更优雅。 一、什么是lambda表达式 Lambda 表达式是 Java 8 引入的特性&#xff0c;用于简化匿名内部类的语法&#xff0c;使代码更简洁&#xff0c;尤其在处理函…

31-35【动手学深度学习】深度学习硬件

1. CPU和GPU 1.1 CPU CPU每秒钟计算的浮点运算数为0.15&#xff0c;GPU为12。GPU的显存很低&#xff0c;16GB&#xff08;可能32G封顶&#xff09;&#xff0c;CPU可以一直插内存。 左边是GPU&#xff08;只能做些很简单的游戏&#xff0c;视频处理&#xff09;&#xff0c;中…

【MySQL成神之路】MySQL常见命令汇总

目录 MySQL常用命令总结 1. 数据库操作 2. 表操作 3. 数据操作&#xff08;DML&#xff09; 4. 索引与优化 5. 用户与权限管理 6. 备份与恢复 7. 事务控制 8. 常用函数 9. 系统状态与日志 总结 MySQL常用命令总结 MySQL作为最流行的关系型数据库之一&#xff0c;提供…

Dify的大语言模型(LLM) AI 应用开发平台-本地部署

前言 今天闲着&#xff0c;捣鼓一下 Dify 这个开源平台&#xff0c;在 mac 系统上&#xff0c;本地部署并运行 Dify 平台&#xff0c;下面记录个人在本地部署Dify 的过程。 Dify是什么&#xff1f; Dify是一个开源的大语言模型&#xff08;LLM&#xff09;应用开发平台&#…

【论文阅读】针对BEV感知的攻击

Understanding the Robustness of 3D Object Detection with Bird’s-Eye-View Representations in Autonomous Driving 这篇文章是发表在CVPR上的一篇文章&#xff0c;针对基于BEV的目标检测算法进行了两类可靠性分析&#xff0c;即恶劣自然条件以及敌对攻击。同时也提出了一…

SonarQube的核心作用与用途

SonarQube作为一个开源的代码质量管理平台&#xff0c;致力于持续分析代码的健康状态&#xff0c;帮助开发团队提升代码质量。以下是其核心作用与用途的详细说明&#xff1a; 1、静态代码分析 SonarQube通过静态代码分析技术&#xff0c;自动识别代码中的潜在问题。它能够检测…

AI工程师系列——面向copilot编程

前言 ​ 笔者已经使用copilot协助开发有一段时间了,但一直没有总结一个协助代码开发的案例,特别是怎么问copilot,按照什么顺序问,哪些方面可以高效的生成需要的代码,这一次,笔者以IP解析需求为例,沉淀一个实践案例,供大家参考 当然,其实也不局限于copilot本身,类似…