# toml-db-release
**Repository Path**: jericho-yu/toml-db-release
## Basic Information
- **Project Name**: toml-db-release
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-04-15
- **Last Updated**: 2026-04-17
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# toml-db-kernal 用户指南
---
## 目录
1. [第一部分:概念说明](#第一部分概念说明)
- [1.1 核心架构与执行流](#11-核心架构与执行流)
- [1.2 存储模型(Append-Only)](#12-存储模型append-only)
- [1.3 热点数据逻辑](#13-热点数据逻辑)
- [1.4 压缩逻辑与策略(COMPACT)](#14-压缩逻辑与策略compact)
- [1.5 关系建模亮点:`REFERENCES ->` 与 `<-`](#15-关系建模亮点references---与--)
- [1.6 嵌套响应格式与传统数据库差异](#16-嵌套响应格式与传统数据库差异)
2. [第二部分:使用说明](#第二部分使用说明)
- [快速启动](#1-快速启动)
- [认证与连接](#2-认证与连接)
- [管理页面](#3-管理页面)
- [WebSocket SQL 协议](#4-websocket-sql-协议)
- [参数绑定](#5-参数绑定)
- [建表(DDL)](#6-建表ddl)
- [表结构变更](#7-表结构变更)
- [数据查询(SELECT)](#8-数据查询select)
- [数据写入(INSERT)](#9-数据写入insert)
- [数据更新(UPDATE)](#10-数据更新update)
- [数据删除(DELETE)](#11-数据删除delete)
- [JOIN 多表连接(重点)](#12-join-多表连接重点)
- [PRELOAD 关系预加载](#13-preload-关系预加载)
- [子查询](#14-子查询)
- [权限系统与用户管理](#15-权限系统与用户管理)
- [存储原理与运维](#16-存储原理与运维)
- [启动模式、日志与终端 SQL 控制台](#17-启动模式日志与终端-sql-控制台)
- [toml-db-driver 使用示例](#18-toml-db-driver-使用示例)
- [附录 A:HTTP 统一响应格式](#附录-ahttp-统一响应格式)
- [附录 B:发布说明](#附录-b发布说明)
---
## 第一部分:概念说明
### 1.1 核心架构与执行流
`toml-db-kernal` 的核心链路可以简化为:
1. 协议层接收 SQL(WebSocket / 控制台 / MySQL 协议适配)
2. 解析层将 SQL 转换为结构化语句(含 WHERE/JOIN/PRELOAD/子查询)
3. 引擎层执行语义(查询、写入、DDL、压缩)
4. 存储层按 Append-Only 规则落盘
5. 格式层输出响应(TOML/JSON,内部以结构化数据流转)
这意味着:**解析、执行、存储、输出** 是分层解耦的;你看到的 SQL 语法能力,最终都会映射到引擎与存储规则。
### 1.2 存储模型(Append-Only)
TOML-DB 不是“原地改页”模型,而是“追加版本”模型:
- `INSERT`:追加新记录
- `UPDATE`:同主键追加新版本
- `DELETE`:追加删除标记(或软删除字段更新)
读取时由索引指向“当前有效版本”。历史版本不会立即删除,而在压缩阶段统一回收。
该模型优势:
- 写入路径简单,容错性好
- 崩溃恢复边界清晰
- 历史版本可追溯(压缩前)
### 1.3 热点数据逻辑
热点数据并不是单独的“缓存表”,而是由访问模式自然形成:
- **读热点**:频繁命中某些主键/索引键
- **写热点**:同一主键高频更新,产生更多历史版本
系统处理方式:
- 读侧:内存索引优先定位最新版本
- 写侧:持续追加,减少原地竞争
- 空间侧:通过 COMPACT 回收热点键积累的旧版本
### 1.4 压缩逻辑与策略(COMPACT)
压缩并非“简单删文件”,而是一次受控重写过程:
1. 扫描版本链
2. 保留每个主键最新有效版本
3. 丢弃覆盖版本与删除版本
4. 重建索引映射并原子切换
触发方式:
- 手动 `COMPACT
` / `COMPACT`
- 自动巡检(`auto_compact_interval`)+ 阈值判断(`compact_stale_ratio`、`compact_min_stale_records`)
### 1.5 关系建模亮点:`REFERENCES ->` 与 `<-`
传统数据库通常只在 DDL 中表达“约束”;TOML-DB 进一步把“关系路径语义”也写入 DDL:
- `REFERENCES users(id) -> Buyer`:定义外键约束 + 正向关系别名路径
- `Books <- books(author_id)`:定义反向一对多关系
这使 PRELOAD 能直接基于关系元数据装配对象结构,而不是每次手写 JOIN + regroup。
### 1.6 嵌套响应格式与传统数据库差异
传统 JOIN 多为“扁平行集”(主表字段重复);TOML-DB 更强调“对象化嵌套响应”:
- 主表字段在顶层
- 关联对象挂在别名 key 下
- 一对多关系天然是数组
这种格式更贴近上层 API/ORM 消费方式,能显著减少应用层二次组装。
---
## 第二部分:使用说明
## 1. 快速启动
### 1.1 启动服务器
访问:[TOML-DB-RELASE](https://gitee.com/jericho-yu/toml-db-release)获取release版本(暂不支持Windows)
```bash
./toml-db
```
首次启动时,程序会自动完成以下操作:
1. 在当前目录生成 `config.toml` 默认配置文件
2. 在数据目录下创建系统表和默认管理员账户
3. 将管理员密码写入 `/initAdminPwd` 文件
你也可以指定配置文件路径:
```bash
./toml-db -C /path/to/config.toml
```
可选参数说明:
- `-C`:配置文件路径(可选,默认 `./config.toml`)
- `-D`:是否以 daemon 模式后台运行(可选,默认 `false`)
示例:
```bash
# 前台模式(默认)
./toml-db
# 指定配置文件
./toml-db -C=./config.toml
# daemon 后台运行
./toml-db -D=true
```
建议:裸启动一次程序然后输入`quit`、`Ctrl+C`退出程序。此时会生成系统默认表、启动密码和默认的配置文件,修改配置文件后再通过`-D=true|false`进行启动。
### 1.2 获取管理员密码
管理员账户在首次启动时自动创建,用户名为 `admin`,密码随机生成。查看密码:
```bash
cat ./data/initAdminPwd
# 输出示例: 394eb8df4848cc713c3a91cba30af0b2
```
> **请妥善保存此密码**,后续登录和管理操作都需要用到。
### 1.3 配置文件说明
启动后生成的 `config.toml` 分为两个段:
```toml
# ---- 网络服务配置 ----
[server]
addr = ":8080" # 监听地址
session_idle_timeout = "2h" # 会话空闲超时(无操作多久断开)
session_absolute_timeout = "12h" # 会话绝对超时(无论是否活跃)
ping_interval = "30s" # WebSocket 心跳间隔
pong_timeout = "10s" # 等待心跳响应的超时时间
max_message_size = "1MB" # 单条消息最大大小
# ---- 存储引擎配置 ----
[storage]
data_dir = "./data" # 数据存储目录
max_file_size = "100MB" # 单个数据文件最大大小(最小 100MB)
auto_compact_enabled = true # 是否开启后台自动压缩
auto_compact_interval = "5m" # 压缩检测间隔
compact_stale_ratio = 0.5 # 过期数据占比阈值(超过则触发压缩)
compact_min_stale_records = 1000 # 最少过期记录数门槛
```
修改配置后重启服务即可生效。
---
## 2. 认证与连接
### 2.1 登录获取会话
所有操作都需要先通过登录获取 `session_id`:
```bash
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "你的密码"}'
```
响应示例:
```json
{
"code": 0,
"msg": "登录成功",
"data": {
"session_id": "abc123...",
"user_id": "uuid-...",
"username": "admin",
"role": "admin"
}
}
```
记下返回的 `session_id`,后续所有请求都需要携带它。
### 2.2 使用 session_id
**HTTP API 请求**:通过请求头携带:
```
Authorization: Bearer
```
**WebSocket 连接**:通过 URL 参数携带:
```
ws://localhost:8080/ws?session=
```
----
### 2.3 其他认证 API
| 方法 | 路径 | 说明 | 认证 |
|------|------|------|------|
| POST | `/api/auth/register` | 注册新用户 | admin |
| POST | `/api/auth/logout` | 登出(销毁会话) | Bearer |
| GET | `/api/auth/profile` | 查看当前用户信息 | Bearer |
#### 注册新用户(仅 admin)
```bash
curl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-H "Authorization: Bearer " \
-d '{"username": "zhangsan", "password": "123456", "role": "manager"}'
```
角色可选值:`admin`、`manager`、`operator`。
#### 登出
```bash
curl -X POST http://localhost:8080/api/auth/logout \
-H "Authorization: Bearer "
```
#### 查看个人信息
```bash
curl http://localhost:8080/api/auth/profile \
-H "Authorization: Bearer "
```
----
## 3. 管理页面
服务启动后,可以通过浏览器访问内置调试页面:`http://localhost:8080/admin`
该页面提供了可视化的 SQL 执行界面,方便测试和调试查询。
## 4. WebSocket SQL 协议
登录成功后,通过 WebSocket 连接发送 SQL 语句来操作数据。
### 4.1 建立连接
```
ws://host:port/ws?session=
```
例如使用 `websocat` 工具(或任何 WebSocket 客户端):
```bash
websocat "ws://localhost:8080/ws?session=你的session_id"
```
### 4.2 发送 SQL 请求
连接建立后,发送 JSON 格式的请求消息:
```json
{
"id": "req-1",
"sql": "SELECT * FROM products WHERE price > ? ORDER BY price DESC LIMIT 10",
"argList": [9.9],
"argDict": {}
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 请求唯一标识,响应中原样返回 |
| `sql` | string | 要执行的 SQL 语句 |
| `argList` | array | 位置参数列表(对应 `?` 占位符) |
| `argDict` | object | 命名参数字典(对应 `:name` 占位符) |
请求也支持 **TOML 格式**,服务端会自动检测:
```toml
id = "req-1"
sql = "SELECT * FROM products"
argList = []
```
### 4.3 接收响应
每条请求都会收到一条响应消息:
```json
{
"id": "req-1",
"code": 0,
"msg": "查询成功",
"data": { ... }
}
```
| 字段 | 说明 |
|------|------|
| `code` | `0` 表示成功,非 0 为错误码 |
| `msg` | 操作结果描述 |
| `data` | 查询结果或操作反馈 |
### 4.4 支持的语句类型
| 分类 | 语句 |
|------|------|
| 数据查询 | SELECT / JOIN / PRELOAD |
| 数据写入 | INSERT / UPDATE / DELETE |
| 建表与变更 | CREATE TABLE / ALTER TABLE / DROP TABLE / TRUNCATE TABLE |
| 元数据 | SHOW TABLES / DESCRIBE |
| 运维 | COMPACT |
---
## 5. 参数绑定
SQL 语句中的占位符支持两种参数传递方式,可以同时混用。
### 5.1 位置参数(argList)
使用 `?` 作为占位符,按顺序传值:
```json
{
"id": "req-1",
"sql": "SELECT * FROM products WHERE price > ? AND category = ?",
"argList": [9.9, "electronics"]
}
```
### 5.2 命名参数(argDict)
使用 `:name` 作为占位符,按名称传值:
```json
{
"id": "req-2",
"sql": "SELECT * FROM users WHERE name = :name AND role = :role",
"argList": [],
"argDict": {
"name": "张三",
"role": "admin"
}
}
```
### 5.3 混合使用
两种方式可以同时使用,命名参数会被转换为位置参数追加到 `argList` 之后:
```json
{
"id": "req-3",
"sql": "SELECT * FROM orders WHERE amount > ? AND status = :status",
"argList": [100],
"argDict": {
"status": "shipped"
}
}
```
> **注意**:JOIN 的 WHERE 子句、PRELOAD WHERE/WITH 之外的所有 SQL 场景均支持上述两种参数绑定方式。PRELOAD WHERE 仅支持字面值。
---
## 6. 建表(DDL)
### 6.1 CREATE TABLE 基本语法
```sql
CREATE TABLE 表名 (
列名 类型 [约束...],
...
)
```
#### 支持的数据类型
| SQL 类型 | 说明 |
|----------|------|
| `INT8` / `INT16` / `INT32` / `INT64` | 有符号整数(8/16/32/64 位) |
| `UINT8` / `UINT16` / `UINT32` / `UINT64` | 无符号整数 |
| `FLOAT32` / `FLOAT64` | 浮点数 |
| `STRING` | 字符串 |
| `BOOL` | 布尔值 |
| `TIMESTAMP` | 时间戳 |
| `UUID` | UUID(通用唯一标识符) |
#### 支持的约束
| 约束 | 说明 |
|------|------|
| `PK` | 主键(每表必须有且仅有一个) |
| `AUTO` | 自增主键(仅整数类型可用) |
| `NOT NULL` | 非空 |
| `UNIQUE` | 唯一 |
| `HASH` | 哈希索引(适合等值查询) |
| `DEFAULT UUID_VN` | UUID 自动生成(N 为 1~7) |
| `CREATE_TIME` | 插入时自动填充创建时间 |
| `UPDATE_TIME` | 插入和更新时自动填充更新时间 |
| `SOFT_DELETE` | 软删除标记(删除时标记时间戳,查询时自动过滤已删记录) |
| `REFERENCES 表名(列名)` | 外键约束 |
#### 示例:基本建表
```json
{
"id": "create-1",
"sql": "CREATE TABLE products (\n id INT64 PK AUTO,\n name STRING NOT NULL UNIQUE,\n price FLOAT64 NOT NULL,\n stock INT32,\n created_at TIMESTAMP CREATE_TIME,\n updated_at TIMESTAMP UPDATE_TIME\n)",
"argList": []
}
```
#### 示例:UUID 主键 + 软删除
```json
{
"id": "create-2",
"sql": "CREATE TABLE orders (\n id UUID PK DEFAULT UUID_V4,\n user_id UUID NOT NULL REFERENCES users(id),\n amount FLOAT64 NOT NULL,\n status STRING,\n deleted_at INT64 SOFT_DELETE,\n created_at INT64 CREATE_TIME,\n updated_at INT64 UPDATE_TIME\n)",
"argList": []
}
```
#### IF NOT EXISTS
如果表已存在则不报错:
```sql
CREATE TABLE IF NOT EXISTS categories (
id INT64 PK AUTO,
name STRING NOT NULL UNIQUE
)
```
### 6.2 关系定义
TOML-DB 支持在建表时声明表之间的关系,用于后续的 JOIN 和 PRELOAD 操作。
#### 正向外键(-> 别名)
在外键约束后追加 `-> 别名`,声明 PRELOAD 加载路径名:
```sql
CREATE TABLE orders (
id INT64 PK AUTO,
user_id INT64 NOT NULL REFERENCES users(id) -> Buyer,
product_id INT64 NOT NULL REFERENCES products(id) -> Product,
amount FLOAT64 NOT NULL,
status STRING
)
```
`-> Buyer` 表示 PRELOAD 时通过 `user_id` 关联加载数据,结果嵌套在 `Buyer` 键下(单个对象)。
#### 反向引用(<- 声明一对多关系)
使用 `<-` 声明当前表与子表的一对多关系(虚拟字段,不占存储空间):
```sql
CREATE TABLE users (
id INT64 PK AUTO,
name STRING NOT NULL,
Books <- books(author_id)
)
```
`Books <- books(author_id)` 表示 `books` 表的 `author_id` 引用当前表主键。PRELOAD 时批量加载所有关联记录(数组)。
#### 完整关系定义示例
```sql
-- 作者表(含反向引用一对多)
CREATE TABLE users (
id INT64 PK AUTO,
name STRING NOT NULL,
Books <- books(author_id)
)
-- 书籍表(外键指向作者和分类)
CREATE TABLE books (
id INT64 PK AUTO,
title STRING NOT NULL,
price FLOAT64 NOT NULL,
author_id INT64 NOT NULL REFERENCES users(id) -> Author,
category_id INT64 REFERENCES categories(id) -> Category
)
```
### 6.3 查看表列表和结构
```sql
-- 列出所有表
SHOW TABLES
-- 查看指定表的结构
DESCRIBE products
-- 或简写
DESC products
```
### 6.4 亮点:`REFERENCES ... ->` 与 `<-` 关系模型
这是 TOML-DB 区别于传统“仅外键约束”数据库的关键特性:
- `REFERENCES users(id) -> Buyer`:
在定义外键约束的同时,声明了**关系别名路径**(`Buyer`),便于 PRELOAD 直接按路径装配对象。
- `Books <- books(author_id)`:
显式声明反向一对多关系,不依赖 ORM 约定推断。
价值:
1. 关系定义进入 DDL,模型语义更清晰
2. 查询层(PRELOAD)可直接复用关系元数据
3. 减少手写 JOIN/ON 的样板代码与错误率
4. 前端/服务层拿到的结果天然是“领域对象结构”而非生硬行集
与传统数据库相比,TOML-DB 把“约束 + 关系路径”合并到一个声明里,强调查询结果可直接用于对象装配。
---
## 7. 表结构变更
### 7.1 添加列
```sql
-- 基本类型与约束
ALTER TABLE products ADD COLUMN description STRING
ALTER TABLE products ADD weight FLOAT64 NOT NULL
-- 外键引用(引用目标表的主键列)
ALTER TABLE orders ADD COLUMN user_id STRING REFERENCES users(id)
-- 外键 + 正向关系别名(用于 PRELOAD 加载关联对象,参见第 13 章)
ALTER TABLE orders ADD COLUMN user_id STRING REFERENCES users(id) -> Buyer
-- 反向引用(通过子表的 FK 指向本表主键,PRELOAD 加载一对多关系,参见第 13 章)
ALTER TABLE authors ADD COLUMN Books <- books(author_id)
```
> **关系定义不受建表时机限制**:无论是 CREATE TABLE 还是 ALTER TABLE,都可以使用 `REFERENCES ... ->` 和 `<-` 声明关系。PRELOAD 功能需要关系先被声明,但不关心声明时机。
### 7.2 删除列
> 主键列不允许删除。删除列会触发全表数据迁移。
```sql
ALTER TABLE products DROP COLUMN description
ALTER TABLE products DROP weight
```
### 7.3 重命名列
> 重命名列会触发全表数据迁移。如果被重命名的列被其他表的外键引用,引用元数据会自动联动更新。
```sql
ALTER TABLE products RENAME COLUMN name TO title
ALTER TABLE products RENAME stock TO quantity
```
### 7.4 重命名表
> 重命名表后,所有引用该表的关系元数据(正向 `REFERENCES` 和反向 `<-`)都会自动更新。
```sql
ALTER TABLE products RENAME TO goods
```
### 7.5 删除表和清空表
```sql
-- 删除表及其全部数据(以 _ 开头的系统表不允许删除)
DROP TABLE products
DROP TABLE IF EXISTS temp_data -- 不存在时不报错
-- 清空表中全部数据但保留表结构(比 DELETE 更快)
TRUNCATE TABLE orders
TRUNCATE orders -- 简写形式
```
> DROP TABLE 和 TRUNCATE TABLE 都需要 `manager` 角色权限。
---
## 8. 数据查询(SELECT)
### 8.1 基本语法
```sql
SELECT 列名 FROM 表名
[WHERE 条件]
[ORDER BY 排序表达式]
[GROUP BY 列名]
[LIMIT 数量] [OFFSET 偏移]
```
#### 查询所有列 / 指定列
```sql
SELECT * FROM products
SELECT id, name, price FROM products
```
#### 条件查询
```sql
SELECT * FROM products WHERE price > ? AND category = ?
```
#### 排序 + 分页
```sql
SELECT * FROM products ORDER BY price DESC LIMIT 10 OFFSET 20
```
### 8.2 WHERE 条件详解
多个条件之间用 `AND` 连接。支持以下操作符:
#### 比较操作符
| 操作符 | 示例 | 说明 |
|--------|------|------|
| `=` | `price = ?` | 等于 |
| `!=` / `<>` | `status != ?` | 不等于 |
| `>` / `<` | `price > ?` | 大于 / 小于 |
| `>=` / `<=` | `age >= ?` | 大于等于 / 小于等于 |
数值和字符串都支持比较。两侧能转为数值时进行数值比较,否则按字符串字典序比较。
#### 模糊匹配(LIKE)
```sql
WHERE name LIKE ?
-- 参数: "%coffee%" 包含 coffee
-- 参数: "coffee%" 以 coffee 开头
-- 参数: "%coffee" 以 coffee 结尾
```
LIKE 匹配 **不区分大小写**。
#### 范围查询
```sql
-- IN 列表
WHERE id IN (?)
-- 参数: [1, 2, 3] 或 "a,b,c"
-- NOT IN
WHERE status NOT IN (?)
-- BETWEEN 范围(含边界)
WHERE price BETWEEN ? AND ?
-- 需要两个参数
```
#### 空值判断
```sql
WHERE deleted_at IS NULL -- 值为空
WHERE email IS NOT NULL -- 值不为空
```
> 空值判断不需要参数占位符。
### 8.3 ORDER BY 排序
支持基本排序、多列排序,以及 **CASE WHEN 自定义排序逻辑**:
```sql
-- 基本升序/降序
SELECT * FROM products ORDER BY price ASC
SELECT * FROM products ORDER BY created_at DESC
-- 多列排序(按调用顺序排列优先级)
SELECT * FROM products ORDER BY category ASC, price DESC
-- CASE WHEN 自定义排序
-- 按角色优先级排序
SELECT * FROM users ORDER BY CASE role
WHEN 'admin' THEN 1
WHEN 'manager' THEN 2
ELSE 3 END
-- 置顶缺货商品,其余按价格降序
SELECT * FROM products ORDER BY CASE WHEN stock = 0 THEN 1 ELSE 0 END, price DESC
```
### 8.4 GROUP BY 与分页
```sql
-- 分组
SELECT * FROM orders GROUP BY buyer_id
-- 手动分页(LIMIT + OFFSET)
SELECT * FROM products LIMIT 10 OFFSET 20
```
### 8.5 查询响应结构
**多条记录**:
```json
{
"total": 100,
"page": 0,
"size": 0,
"max_page": 0,
"data": [...]
}
```
**单条记录**(LIMIT 1):
```json
{
"total": 1,
"page": 1,
"size": 1,
"max_page": 1,
"data": {...}
}
```
---
## 9. 数据写入(INSERT)
### 9.1 基本语法
```sql
INSERT INTO 表名 (列1, 列2, ...) VALUES (?, ?, ...)
```
以下标签声明的字段 **无需手动指定**,服务端会自动注入:
| 标签 | 自动行为 |
|------|---------|
| `PK AUTO` | 自增主键 ID |
| `DEFAULT UUID_VN` | UUID 自动生成 |
| `CREATE_TIME` | 创建时间戳 |
| `UPDATE_TIME` | 更新时间戳 |
### 9.2 插入示例
```json
{
"id": "insert-1",
"sql": "INSERT INTO products (name, price, stock) VALUES (?, ?, ?)",
"argList": ["Coffee", 9.9, 100]
}
```
响应中返回包含自动生成字段的完整记录:
```json
{
"id": "insert-1",
"code": 0,
"msg": "插入成功",
"data": {
"datum": {
"id": "1",
"name": "Coffee",
"price": 9.9,
"stock": 100,
"created_at": "2026-04-13T12:00:00Z",
"updated_at": "2026-04-13T12:00:00Z"
}
}
}
```
### 9.3 全自动插入
如果表的所有业务字段都有默认值或自动标签,可以不传任何字段:
```sql
INSERT INTO logs () VALUES ()
```
---
## 10. 数据更新(UPDATE)
### 10.1 基本语法
```sql
UPDATE 表名 SET 列1 = ?, 列2 = ? WHERE 主键列 = ?
```
**重要约束**:WHERE 中 **必须包含主键条件**。
### 10.2 行为说明
- `UPDATE_TIME` 字段自动更新为当前时间
- `CREATE_TIME` 字段受保护,不可修改
- 由于 Append-Only 存储模型,UPDATE 内部流程是:读取旧记录 → 合并 SET 值 → 写入完整新记录
### 10.3 更新示例
```json
{
"id": "update-1",
"sql": "UPDATE products SET price = ?, stock = ? WHERE id = ?",
"argList": [19.9, 50, "1"]
}
```
响应返回合并后的完整记录。
---
## 11. 数据删除(DELETE)
### 11.1 基本语法
```sql
DELETE FROM 表名 WHERE 主键列 = ?
```
**重要约束**:WHERE 中 **必须包含主键条件**。
### 11.2 删除行为
- 如果表定义了 `SOFT_DELETE` 字段 → 执行 **软删除**(标记删除时间),数据保留在存储中,后续 SELECT 自动过滤
- 否则执行 **物理删除**
### 11.3 删除示例
```json
{
"id": "delete-1",
"sql": "DELETE FROM products WHERE id = ?",
"argList": ["1"]
}
```
---
## 12. JOIN 多表连接**(重点)**
TOML-DB 完整支持 5 种标准 JOIN 类型。与传统 SQL 不同,**JOIN 结果采用嵌套 JSON 结构** —— 主表字段在顶层,JOIN 表数据嵌套在以别名(或表名)为 key 的子对象中。
### 12.1 语法
```sql
SELECT 列名 FROM 主表 [别名]
[JOIN类型] 连接表 [别名] ON 连接条件
[JOIN类型] 连接表 [别名] ON 连接条件
[WHERE 条件]
[ORDER BY 排序]
[LIMIT 数量] [OFFSET 偏移]
```
### 12.2 JOIN 类型
| 语法 | 说明 |
|------|------|
| `JOIN` / `INNER JOIN` | 内连接:仅返回两表均匹配的行 |
| `LEFT JOIN` / `LEFT OUTER JOIN` | 左外连接:左表全保留 + 右表匹配(无匹配时为 null) |
| `RIGHT JOIN` / `RIGHT OUTER JOIN` | 右外连接:右表全保留 + 左表匹配 |
| `FULL OUTER JOIN` / `FULL JOIN` | 全外连接:两表全部(无匹配的一侧为 null) |
| `CROSS JOIN` | 交叉连接:笛卡尔积,无需 ON 条件 |
### 12.3 表别名
```sql
-- 空格分隔
SELECT * FROM orders o LEFT JOIN users u ON u.id = o.user_id
-- AS 关键字
SELECT * FROM orders AS o LEFT JOIN users AS u ON u.id = o.user_id
```
### 12.4 ON 条件
ON 条件使用 `表.列 = 表.列` 格式,多个条件用 `AND` 连接。非 CROSS JOIN 必须指定 ON 条件:
```sql
ON u.id = o.user_id
ON u.id = o.user_id AND u.tenant_id = o.tenant_id
```
### 12.5 结果结构示例
**LEFT JOIN 查询**:
```json
{
"id": "req-1",
"sql": "SELECT * FROM orders o LEFT JOIN users u ON u.id = o.user_id",
"argList": []
}
```
响应(嵌套 JSON):
```json
{
"data": {
"total": 3,
"data": [
{
"id": 1, "user_id": 10, "amount": 199.0, "status": "shipped",
"u": { "id": 10, "name": "Alice", "email": "alice@example.com" }
},
{
"id": 2, "user_id": 20, "amount": 350.0, "status": "pending",
"u": { "id": 20, "name": "Bob", "email": "bob@example.com" }
},
{
"id": 3, "user_id": 999, "amount": 50.0, "status": "cancelled",
"u": null
}
]
}
}
```
关键特征:
- 主表字段放在顶层
- JOIN 表数据嵌套在 **别名**(此处为 `u`)key 下
- 无匹配时(LEFT JOIN),嵌套值为 `null`
- 多表 JOIN 时,每个连接表各自一个嵌套 key
### 12.6 带 WHERE 的 JOIN
WHERE 中可以通过 `表.列` 限定字段所属表:
```json
{
"id": "req-2",
"sql": "SELECT * FROM orders o INNER JOIN users u ON u.id = o.user_id WHERE o.amount > ? AND u.name = ?",
"argList": [100, "Alice"]
}
```
### 11.7 多表 JOIN
```sql
SELECT * FROM orders o
LEFT JOIN users u ON u.id = o.user_id
INNER JOIN products p ON p.id = o.product_id
WHERE o.amount > ?
```
响应包含两层嵌套:
```json
{
"id": 1, "user_id": 10, "product_id": 5, "amount": 199.0,
"u": { "id": 10, "name": "Alice" },
"p": { "id": 5, "name": "键盘", "price": 199.0 }
}
```
### 12.8 CROSS JOIN 笛卡尔积
```sql
SELECT * FROM colors CROSS JOIN sizes
```
无需 ON 条件,返回两表的笛卡尔积。
### 12.9 注意事项
- JOIN 使用 **哈希索引匹配** 实现,适合等值连接场景
- JOIN 涉及的所有表都需要当前用户具有查询权限
- 嵌套 key **优先使用别名**,无别名时使用表名
- 多个 JOIN 按书写顺序依次执行,后续 JOIN 的 ON 条件可以引用前面 JOIN 的表
- JOIN 查询的 WHERE 子句 **完全支持位置参数和命名参数**
### 12.10 与传统数据库响应格式差异(嵌套响应)
传统 SQL 数据库的 JOIN 结果通常是“扁平行集”(每行重复主表字段);TOML-DB 默认返回**嵌套结构**:
- 主表字段保留在顶层
- 关联表以别名(或表名)作为子对象键
- 一对多关系可直接返回数组
传统扁平行示意:
```text
order_id | amount | user_id | user_name
1 | 99.0 | 10 | Alice
2 | 50.0 | 10 | Alice
```
TOML-DB 嵌套行示意:
```json
{
"id": 1,
"amount": 99.0,
"u": { "id": 10, "name": "Alice" }
}
```
这种结构更贴近 API 输出与对象模型,减少应用层二次 regroup/merge 的处理成本。
---
## 13. PRELOAD 关系预加载
PRELOAD 允许在一次查询中自动加载关联数据,无需手动编写 JOIN 条件。通过 DDL 中定义的关系元数据,PRELOAD 自动完成关联匹配和数据装配,有效避免 N+1 查询问题。
> **前置条件**:使用 PRELOAD 前,必须在 CREATE TABLE 中通过 `-> 别名` 或 `<-` 声明好关系(参见 [6.2 关系定义](#6.2-关系定义))。
### 13.1 与 JOIN 的区别
| 对比项 | JOIN | PRELOAD |
|--------|------|---------|
| 连接条件 | 手动指定 ON 条件 | 基于 DDL 定义的关系自动关联 |
| 结果结构 | 嵌套对象(别名为 key) | 嵌套对象或数组(路径名为 key) |
| 适用场景 | 灵活的多表关联 | 实体关系的自动加载 |
### 13.2 语法
```sql
SELECT 列名 FROM 表名
PRELOAD {
(路径),
(路径 WHERE 条件),
(路径 WHERE 条件 WITH 计数条件),
(*)
}
[WHERE 主查询条件]
[ORDER BY 排序]
[LIMIT 数量]
```
### 13.3 路径语法
| 路径形式 | 说明 | 示例 |
|----------|------|------|
| `(Name)` | 单层关系 | `(Author)` — 加载关联作者 |
| `(A.B)` | 多层级嵌套路径(最深 5 层) | `(Author.Books)` — 加载作者及其书籍 |
| `(*)` | 通配符:展开所有直接关系 | `(*)` — 加载所有正向 FK 和反向引用 |
### 13.4 正向外键预加载(多对一 → 单个对象)
假设建表时定义了:
```sql
CREATE TABLE books (
id INT64 PK AUTO,
title STRING NOT NULL,
price FLOAT64,
author_id INT64 REFERENCES authors(id) -> Author
)
```
查询书籍并加载作者:
```json
{
"id": "preload-1",
"sql": "SELECT * FROM books PRELOAD { (Author) }",
"argList": []
}
```
响应:
```json
{
"data": {
"total": 3,
"data": [
{
"id": 1, "title": "Go 编程实战", "price": 89.0, "author_id": 42,
"Author": { "id": 42, "name": "张三" }
},
{
"id": 2, "title": "Go 并发模式", "price": 75.0, "author_id": 42,
"Author": { "id": 42, "name": "张三" }
}
]
}
}
```
正向外键的结果为 **单个嵌套对象**(或 null)。
### 13.5 反向引用预加载(一对多 → 数组)
假设建表时定义了:
```sql
CREATE TABLE authors (
id INT64 PK AUTO,
name STRING NOT NULL,
Books <- books(author_id)
)
```
查询作者并加载其所有书籍:
```json
{
"id": "preload-2",
"sql": "SELECT * FROM authors PRELOAD { (Books) }",
"argList": []
}
```
响应:
```json
{
"data": {
"total": 2,
"data": [
{
"id": 42, "name": "张三",
"Books": [
{ "id": 1, "title": "Go 编程实战", "price": 89.0, "author_id": 42 },
{ "id": 2, "title": "Go 并发模式", "price": 75.0, "author_id": 42 }
]
},
{
"id": 43, "name": "李四",
"Books": [
{ "id": 3, "title": "Rust 入门", "price": 99.0, "author_id": 43 }
]
}
]
}
}
```
反向引用的结果为 **嵌套数组**(可能为空数组 `[]`)。
### 13.6 通配符预加载
一次加载当前表的所有直接关系(一层,不递归):
```sql
SELECT * FROM books PRELOAD { (*) }
```
等价于显式列出所有直接关系:
```sql
SELECT * FROM books PRELOAD { (Author), (Category) }
```
### 13.7 PRELOAD WHERE — 行级过滤
对关联数据进行过滤。使用 **字面值**(不支持 `?` 占位符):
```sql
SELECT * FROM authors PRELOAD {
(Books WHERE price > 50 AND status = 'published')
}
```
规则:
- **正向外键**:不满足条件的行,嵌套值置为 `null`
- **反向引用**:仅返回满足条件的子记录,不影响主表行的保留
### 13.8 PRELOAD WITH — 基于子记录数量过滤主表
语法:`count([内部条件]) 比较符 数值`
| WITH 表达式 | 含义 |
|------------|------|
| `count() > 0` | 至少有 1 条子记录 |
| `count() = 0` | 没有子记录 |
| `count(price > 50) >= 3` | 价格大于 50 的子记录至少 3 条 |
示例:查询至少出版了 2 本高价书的作者
```sql
SELECT * FROM authors PRELOAD {
(Books WITH count(price > 100) >= 2)
}
```
### 13.9 WHERE + WITH 组合
先过滤子记录,再按过滤后的数量过滤主记录:
```sql
SELECT * FROM authors PRELOAD {
(Books WHERE status = 'published' WITH count(price > 50) > 0)
} WHERE name LIKE ?
-- argList: ["%张%"]
```
### 13.10 多层级路径
查询书籍并加载作者信息以及作者的其他书籍:
```json
{
"id": "preload-5",
"sql": "SELECT * FROM books PRELOAD { (Author.Books) } WHERE id = ? LIMIT 1",
"argList": [1]
}
```
响应:
```json
{
"data": {
"id": 1, "title": "Go 编程实战", "price": 89.0, "author_id": 42,
"Author": {
"id": 42, "name": "张三",
"Books": [
{ "id": 1, "title": "Go 编程实战", "price": 89.0, "author_id": 42 },
{ "id": 2, "title": "Go 并发模式", "price": 75.0, "author_id": 42 }
]
}
}
}
```
### 13.11 注意事项
- 使用 PRELOAD 前必须在 CREATE TABLE 中通过 `-> 别名` 或 `<-` 声明关系
- 路径最大深度 **5 层**
- 正向外键内部通过 LEFT JOIN 实现,反向引用通过批量分组加载实现
- PRELOAD WHERE 使用字面值,不支持 `?` 占位符
- 通配符 `(*)` 只展开直接关系,不递归
- 多个 PRELOAD 项可同时加载:`PRELOAD { (Author), (Category), (Tags) }`
---
## 14. 子查询
子查询允许在 WHERE 条件中嵌入另一个 SELECT 查询。子查询在执行前被 **预解析** 为具体值——IN 子查询转换为值列表,标量子查询转换为单个值,EXISTS 转换为布尔判断——然后主查询使用这些具体值进行过滤。
### 14.1 三种子查询形式
| 形式 | 语法 | 说明 |
|------|------|------|
| **IN / NOT IN** | `field IN (SELECT col FROM ...)` | 字段值是否在子查询结果集中 |
| **标量比较** | `field > (SELECT col FROM ... LIMIT 1)` | 与子查询的单个标量值比较 |
| **EXISTS / NOT EXISTS** | `EXISTS (SELECT 1 FROM ...)` | 子查询是否返回至少一行 |
### 14.2 参数绑定
子查询中的 `?` 占位符从外层 `argList` 中 **按出现顺序依次消耗**:
```json
{
"sql": "SELECT * FROM users WHERE age > ? AND id IN (SELECT user_id FROM orders WHERE amount > ?) AND status = ?",
"argList": [18, 100, "active"]
}
```
参数分配:
- 第 1 个 `?`(18)→ `age > 18`
- 第 2 个 `?`(100)→ 子查询中 `amount > 100`
- 第 3 个 `?`(`active`)→ `status = 'active'`
### 14.3 IN / NOT IN 子查询
查询所有下过订单金额超过 100 的用户:
```json
{
"id": "sub-1",
"sql": "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > ?)",
"argList": [100]
}
```
内部执行过程:
1. 先执行子查询 `SELECT user_id FROM orders WHERE amount > 100`,得到 `[10, 20, 42]`
2. 主查询变为 `SELECT * FROM users WHERE id IN [10, 20, 42]`
### 14.4 标量子查询
查询价格高于最低价商品的商品:
```json
{
"id": "sub-3",
"sql": "SELECT * FROM products WHERE price > (SELECT price FROM products ORDER BY price LIMIT 1)",
"argList": []
}
```
标量子查询取结果的 **第一行第一列** 作为比较值。建议搭配 `LIMIT 1`。
### 14.5 EXISTS / NOT EXISTS
查询至少有一个订单的用户:
```json
{
"id": "sub-4",
"sql": "SELECT * FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE user_id = ?)",
"argList": [42]
}
```
### 14.6 嵌套限制
子查询支持嵌套,最大深度为 **3 层**:
```sql
-- 2 层嵌套(允许)
WHERE id IN (
SELECT user_id FROM orders
WHERE product_id IN (SELECT id FROM products WHERE category = ?)
)
```
### 14.7 PRELOAD 中的子查询
PRELOAD WHERE 和 WITH 表达式中也可以包含子查询,同样会在执行前被预解析为字面值:
```sql
SELECT * FROM authors PRELOAD {
(Books WHERE category_id IN (SELECT id FROM categories WHERE name = 'fiction'))
}
```
> 注意:PRELOAD 子查询中不支持 `?` 占位符(因 PRELOAD WHERE 本身使用字面值语法)。
---
## 15. 权限系统与用户管理
### 15.1 角色体系
| 角色 | 说明 | 权限范围 |
|------|------|---------|
| **admin** | 管理员 | 所有权限,可管理用户和授权 |
| **manager** | 管理者 | 已授权表的增删改查 + 全部 DDL |
| **operator** | 操作者 | 已授权表的查询 + COMPACT/MIGRATE |
### 15.2 权限矩阵
| 操作 | admin | manager | operator |
|------|-------|---------|----------|
| SELECT 已授权表 | 全部 | ✅ | ✅ |
| INSERT / UPDATE / DELETE | 全部 | ✅(已授权表) | ❌ |
| CREATE / ALTER / DROP / TRUNCATE | 全部 | ✅ | ❌ |
| COMPACT | 全部 | ❌ | ✅(已授权表) |
| SHOW TABLES / DESCRIBE | 全部 | ✅ | ✅ |
| 用户管理与授权 | ✅ | ❌ | ❌ |
### 15.3 授权管理(仅 admin)
#### 授予权限
```bash
curl -X POST http://localhost:8080/api/admin/privilege \
-H "Content-Type: application/json" \
-H "Authorization: Bearer " \
-d '{
"user_id": "目标用户的UUID",
"table_name": "products",
"privilege": "manager"
}'
```
`privilege` 可选值:
- `manager`:该用户可对指定表执行 query/insert/update/delete
- `operator`:该用户可对指定表执行 query/compact/migrate
#### 撤销权限
```bash
curl -X DELETE http://localhost:8080/api/admin/privilege \
-H "Content-Type: application/json" \
-H "Authorization: Bearer " \
-d '{
"user_id": "目标用户的UUID",
"table_name": "products",
"privilege": "manager"
}'
```
### 15.4 系统表保护
以 `_` 开头的系统表(如 `_sys_user`、`_sys_user_privilege`)禁止非 admin 直接操作。即使 manager 角色也无法访问系统表。
---
## 16. 存储原理与运维
### 16.1 Append-Only 存储模型
TOML-DB 采用 **Append-Only(追加写入)** 存储引擎,这是它最核心的设计特点。与传统数据库“原地覆盖页”不同,TOML-DB 的写路径是:
1. **INSERT**:直接追加一条新记录
2. **UPDATE**:按同主键追加“新版本记录”
3. **DELETE**:追加删除标记(或软删除字段更新)
典型记录演进如下:
```
data_0.db: [记录1] [记录1-更新版] [记录2] [记录1-删除标记] [记录3]
↑ ↑ ↑
同ID新版本覆盖 新插入 软删除(追加标记)
```
**核心规则**:数据一旦落盘,原则上不做原地修改;读取时总是按“主键索引指向的最新版本”返回。
这使得系统具备天然的“写放大换稳定性”特征:
- 写入路径简单、故障恢复容易
- 数据一致性依赖“追加成功 + 索引切换”
- 历史版本在压缩前可追溯
**优势**:
- **天然容错**:写入中途断电不会损坏已有数据
- **原子性**:追加操作要么完全成功,要么完全不生效
- **版本追溯**:旧版本数据在被清理前一直可读
**代价**:需要定期执行 **COMPACT(压缩)** 来清理过期数据,释放磁盘空间。
### 16.2 自动分片
单表数据文件达到上限(默认 100MB)时自动拆分为多个文件:
```
./data/products/
├── data_0.db # 第一块(0~100MB)
├── data_1.db # 第二块(100~200MB)
└── data_2.db # 第三块(200~300MB,以此类推)
```
对上层查询而言,分片是透明的。
### 16.3 热点数据逻辑(Hot Data)
在 Append-Only 模型下,“热数据”本质是:
- 更新频繁、版本迭代快的主键记录
- 高频查询命中的索引键(PK / HASH / INDEX)
TOML-DB 对热点数据的处理逻辑可概括为:
1. **读路径热点**:优先走内存索引定位到最新版本,避免全表扫描
2. **写路径热点**:持续追加新版本,不做页级锁竞争与原地改写
3. **空间热点副作用**:热点记录会产生更多历史版本,增加“过期数据比例”
4. **治理手段**:依赖 COMPACT 定期回收历史版本,降低无效 I/O
因此,热点访问不是通过复杂缓存层实现,而是通过“内存索引 + 追加写 + 压缩回收”形成闭环。
### 16.4 索引与缓存
- **主键索引**:表打开时自动加载到内存
- **普通索引**(`INDEX` / `HASH`):同样常驻内存
- 查询时优先走内存索引,避免全表扫描
### 16.5 数据目录结构
```
./data/
├── initAdminPwd # 初始化的管理员密码
├── _sys_user/ # 系统表:用户
│ ├── data_0.db
│ └── schema.json
├── _sys_user_privilege/ # 系统表:权限
│ ├── data_0.db
│ └── schema.json
└── YourTableName/ # 业务表
├── data_0.db # 第一块数据文件
├── data_1.db # 后续滚动生成的文件
└── schema.json # 表结构定义(DDL 创建的表才有)
```
### 16.6 COMPACT 压缩
COMPACT 用于清理旧版本记录和已软删除的数据,释放磁盘空间。
压缩核心策略:
1. **按主键只保留最新有效版本**
2. **丢弃已删除或已被覆盖的历史记录**
3. **重建压缩后数据文件与索引映射**
4. **原子切换新旧文件**(避免中途失败导致读写异常)
触发策略分两类:
- **手动触发**:适合大批量导入/更新后立即回收空间
- **自动触发**:按时间间隔巡检,结合“过期比例 + 最小过期数”阈值决定是否执行
建议经验:
- 更新频繁(热点明显)的业务表:提高压缩频率
- 冷数据表:延长压缩间隔,减少无意义重写
- 观察 `compact_stale_ratio` 与实际磁盘增长,动态调参
#### 手动压缩
```json
{
"id": "compact-1",
"sql": "COMPACT products",
"argList": []
}
```
或压缩全部表:
```json
{
"id": "compact-all",
"sql": "COMPACT",
"argList": []
}
```
#### 自动压缩
通过 `config.toml` 配置后台自动压缩:
```toml
[storage]
auto_compact_enabled = true # 开关
auto_compact_interval = "5m" # 检测间隔
compact_stale_ratio = 0.5 # 过期数据占比超过 50% 时触发
compact_min_stale_records = 1000 # 至少 1000 条过期记录才触发(避免小表频繁压缩)
```
#### 压缩响应
返回压缩统计信息(清理的记录数等)。
---
### 16.7 与传统存储引擎的差异总结
| 维度 | 传统页式引擎(常见) | TOML-DB(Append-Only) |
|------|----------------------|-------------------------|
| 更新方式 | 原地修改页 | 追加新版本 |
| 删除方式 | 页内标记/回收 | 追加删除标记,压缩时清理 |
| 崩溃恢复 | 依赖 WAL/Checkpoint | 依赖追加完整性与索引恢复 |
| 热点冲突 | 可能产生页锁竞争 | 以追加为主,冲突模型更简单 |
| 空间回收 | 后台 vacuum/整理 | COMPACT 主动/自动回收 |
---
## 17. 启动模式、日志与终端 SQL 控制台
### 17.1 前台 / daemon 启动模式
- 前台模式(默认):`-D=false`,输出同时写控制台和日志文件。
- daemon 模式:`-D=true`,进程后台运行,日志仅写文件。
```bash
./toml-db -D=false
./toml-db -D=true
```
### 17.2 日志配置与轮转
配置文件中的 `[log]` 段用于控制日志目录与滚动策略:
```toml
[log]
dir = "./logs"
max_size = "100MB"
max_files = 10
```
说明:
- `dir`:日志目录
- `max_size`:单个日志文件最大大小,超限后自动滚动
- `max_files`:最多保留日志文件数(含当前),超出自动删除最旧文件
默认日志文件为:`./logs/server.log`。
### 17.3 终端 SQL 控制台(前台模式)
服务启动后,前台终端会自动进入 SQL 控制台(daemon 模式不启用)。
特性:
- 输入 SQL,使用 `;` 结尾执行
- 支持多行 SQL 输入
- 支持 `↑ / ↓` 浏览历史记录
- `Ctrl+C` 清空当前输入(不退出进程)
- `exit` 或 `quit` 然后按 `Ctrl+C` 退出控制台输入循环
- 终端执行结果输出为 **TOML**(仅 webServer 对外协议支持 TOML/JSON 转换)
示例:
```sql
SHOW TABLES;
DESCRIBE users;
SELECT * FROM users LIMIT 5;
```
---
## 附录 B:发布说明
`toml-db` 默认以闭源可执行文件形态交付,推荐将 `toml-db-kernal/cmd` 目录下的 `Makefile` 作为统一构建入口。该 `Makefile` 已内置 `release`、`debug`、`upx`、`size` 与 `clean` 五个目标,便于在发布、排障与体积优化之间切换。
### B.1 构建目标
在 `toml-db-kernal/cmd` 目录执行:
```bash
make release
make debug
make upx
make size
make clean
```
含义如下:
- `make release`:生成发布版二进制 `toml-db`
- 使用 `-trimpath`
- 使用 `-ldflags="-s -w -buildid="` 去除调试信息并缩小体积
- `make debug`:生成调试版二进制 `toml-db-debug`
- 使用 `-tags debug`
- 保留更完整的调试能力,便于排查问题
- `make upx`:先构建 `release`,再对 `toml-db` 执行 `upx --best --lzma` 压缩
- `make size`:查看当前 `toml-db` / `toml-db-debug` 产物体积
- `make clean`:删除构建产物
### B.2 release / debug 的差异
当前构建已通过 Go build tag 将 `pprof` 行为拆分:
- `debug` 构建(`//go:build debug`)
- 自动启动本地 `pprof`
- 监听地址:`127.0.0.1:6060`
- 适合开发调试、性能采样、压测分析
- `release` 构建(`//go:build !debug`)
- 不启动 `pprof`
- 适合正式交付,体积更小、暴露面更低
因此,推荐策略是:
- 对外发布默认提供 `toml-db`
- 内部排障或性能测试时使用 `toml-db-debug`
- 如果需要进一步缩小体积,可对 `toml-db` 执行 `make upx`
### B.3 推荐发布产物
建议对用户交付以下内容:
1. `toml-db`(release 产物)
2. `config.toml` 示例配置
3. 本 README 文档
4. (可选)官方客户端或协议说明,如 `toml-db-driver`
其中:
- `toml-db`:默认正式发布版本
- `toml-db-debug`:仅建议内部保留,不建议直接提供给最终用户
- `UPX` 压缩后的 `toml-db`:适合对包体积敏感的场景,但建议在目标平台完成启动验证后再发布
### B.4 README 同步策略
`toml-db-kernal/readme.md` 作为主文档;`toml-db-release/README.md` 必须保持与其同步。后续凡是发布方式、构建命令、调试能力、交付物说明发生变更,均应以本文件为准,并整段镜像同步到 `toml-db-release/README.md`。