从0到1手写一个demo级别MySQL项目
MiniMySQL Demo 项目设计文档
一、项目定位
1. 项目名称
MiniMySQL:从 0 到 1 手写一个简化版关系型数据库
2. 项目目标
本项目不是完整复刻 MySQL,而是实现一个具备数据库核心能力的教学型数据库系统。
最终学生需要实现:
- 支持基础 SQL 语句解析与执行。
- 支持表结构创建、数据插入、查询、更新、删除。
- 支持数据持久化到磁盘文件。
- 支持简单索引,例如 B+ 树索引。
- 支持简单事务,包括 begin、commit、rollback。
- 支持基础日志与崩溃恢复思想。
- 支持简单查询优化,例如有索引用索引、无索引全表扫描。
- 支持命令行客户端或简单 Web 控制台。
二、项目适合人群
适合已经具备以下基础的学生:
- Java 基础。
- 集合、IO、文件读写。
- 基础数据结构,例如数组、链表、树、哈希表。
- 了解 SQL 基本语法。
- 了解 MySQL 的基本使用。
推荐技术栈:
语言:Java 17
构建工具:Maven
测试框架:JUnit
命令行交互:Scanner / JLine
可视化扩展:Spring Boot + Vue,可选
三、项目整体架构
flowchart TD
A[用户输入 SQL] --> B[词法分析 Lexer]
B --> C[语法分析 Parser]
C --> D[AST 抽象语法树]
D --> E[执行计划 Planner]
E --> F[执行器 Executor]
F --> G[事务管理 Transaction Manager]
F --> H[表管理 Catalog Manager]
F --> I[索引管理 Index Manager]
F --> J[存储引擎 Storage Engine]
G --> K[锁管理 Lock Manager]
G --> L[日志管理 Log Manager]
J --> M[缓冲池 Buffer Pool]
M --> N[磁盘页 Page File]
I --> O[B+Tree 索引文件]
L --> P[Undo Log / Redo Log]
四、最终支持的 SQL 范围
1. DDL 表结构语句
create table user (
id int primary key,
name varchar,
age int
);
drop table user;
show tables;
desc user;
2. DML 数据操作语句
insert into user values (1, '张三', 18);
select * from user;
select id, name from user where age = 18;
update user set age = 20 where id = 1;
delete from user where id = 1;
3. 索引语句
create index idx_user_age on user(age);
drop index idx_user_age;
show index from user;
4. 事务语句
begin;
insert into user values (2, '李四', 19);
rollback;
commit;
5. 暂不支持的高级功能
Demo 阶段不建议实现:
join 多表连接
group by
order by
having
子查询
视图
存储过程
复杂优化器
MVCC 完整版本链
分布式事务
五、项目模块划分
1. SQL 解析模块
负责把用户输入的 SQL 字符串转换成系统可以识别的结构。
核心功能:
示例:
select id, name from user where age = 18;
解析后变成:
SelectStatement
- columns: id, name
- tableName: user
- where:
- column: age
- operator: =
- value: 18
2. 元数据管理模块 Catalog
负责管理数据库中有哪些表、表有哪些字段、字段类型、主键、索引等信息。
核心功能:
示例元数据:
{
"tableName": "user",
"columns": [
{"name": "id", "type": "int", "primaryKey": true},
{"name": "name", "type": "varchar"},
{"name": "age", "type": "int"}
],
"indexes": [
{"name": "idx_user_age", "column": "age"}
]
}
3. 存储引擎模块 Storage Engine
负责把数据真正存储到磁盘文件中。
核心功能:
推荐页大小:
Page Size = 4096 字节
表文件示例:
data/
└── default/
├── user.tbl
├── user.meta
├── idx_user_age.idx
└── minidb.log
4. 缓冲池模块 Buffer Pool
负责减少频繁磁盘 IO。
核心功能:
简化设计:
BufferPool 默认缓存 64 个 Page
PageId = tableName + pageNo
5. 执行器模块 Executor
负责真正执行 AST 对应的操作。
核心功能:
执行流程:
SQL 字符串
-> Lexer
-> Parser
-> AST
-> Planner
-> Executor
-> Storage Engine
-> 返回结果
6. 索引模块 Index Manager
索引建议实现 B+ 树。
核心功能:
索引结构:
key -> RowId
其中:
RowId = pageNo + slotNo
例如:
age = 18 -> RowId(pageNo=1, slotNo=3)
7. 查询优化器 Planner
Demo 阶段只做简单优化。
核心逻辑:
如果 where 条件字段有索引:
使用 IndexScan
否则:
使用 FullTableScan
示例:
select * from user where age = 18;
如果 age 上有索引,则执行计划为:
IndexScan(table=user, index=idx_user_age, condition=age=18)
如果没有索引,则执行计划为:
FullTableScan(table=user, condition=age=18)
8. 事务模块 Transaction Manager
实现基础事务能力。
核心功能:
简化事务模型:
begin;
insert into user values (1, '张三', 18);
rollback;
rollback 后,插入的数据应该消失。
9. 日志模块 Log Manager
日志用于支撑事务和恢复。
建议分两类:
Undo Log
用于回滚。
例如执行:
update user set age = 20 where id = 1;
Undo Log 记录:
事务 1001 修改 user 表 RowId(1,3)
修改前数据:id=1, name=张三, age=18
rollback 时恢复原值。
Redo Log
用于崩溃恢复。
例如 commit 后系统崩溃,数据还没刷盘,重启后可以根据 redo log 重新恢复。
10. 锁管理模块 Lock Manager
Demo 阶段可以实现简单表锁或行锁。
推荐路线:
第一版只做表锁:
select:共享锁 S Lock
insert/update/delete:排他锁 X Lock
第二版再扩展行锁:
RowId 级别加锁
锁冲突规则:
六、阶段开发计划
阶段一:项目骨架与命令行客户端
阶段目标
搭建项目基础结构,让用户可以输入 SQL,并看到系统响应。
需要实现
1. Maven 项目初始化
2. Main 入口类
3. 命令行 SQL 输入
4. 简单命令分发
5. exit 退出程序
6. help 查看支持命令
示例效果
MiniMySQL> help;
支持命令:
create table ...
insert into ...
select ...
exit;
MiniMySQL> exit;
bye.
推荐目录结构
mini-mysql/
├── pom.xml
├── data/
└── src/main/java/com/minimysql/
├── MiniMysqlApplication.java
├── cli/
├── sql/
├── parser/
├── executor/
├── catalog/
├── storage/
├── index/
├── transaction/
├── log/
└── common/
验收标准
学生运行程序后,可以进入命令行交互环境。
阶段二:词法分析 Lexer
阶段目标
把 SQL 字符串拆解成 Token。
需要实现
1. 识别关键字:select、insert、update、delete、create、table、where
2. 识别标识符:表名、字段名
3. 识别数字:123
4. 识别字符串:'张三'
5. 识别符号:*, =, (, ), ,, ;
6. 输出 Token 列表
示例
输入:
select id, name from user where age = 18;
输出:
SELECT
IDENTIFIER(id)
COMMA
IDENTIFIER(name)
FROM
IDENTIFIER(user)
WHERE
IDENTIFIER(age)
EQ
NUMBER(18)
SEMICOLON
验收标准
能够正确打印 SQL 对应的 Token 列表。
阶段三:语法分析 Parser 与 AST
阶段目标
把 Token 转换成 AST 对象。
需要实现
1. CreateTableStatement
2. InsertStatement
3. SelectStatement
4. UpdateStatement
5. DeleteStatement
6. CreateIndexStatement
7. BeginStatement
8. CommitStatement
9. RollbackStatement
示例 AST
class SelectStatement {
private List<String> columns;
private String tableName;
private WhereCondition whereCondition;
}
支持语法
select * from user;
select id, name from user where age = 18;
insert into user values (1, '张三', 18);
验收标准
输入 SQL 后,可以打印 AST 结构。
阶段四:内存版数据库
阶段目标
先不考虑磁盘,使用 Java 内存集合实现 create、insert、select。
需要实现
1. 内存中保存数据库表
2. create table 创建表
3. insert 插入数据
4. select 查询数据
5. where 简单过滤
内存结构示例
Map<String, Table> tables = new HashMap<>();
class Table {
private String tableName;
private List<Column> columns;
private List<Row> rows;
}
示例效果
create table user (
id int,
name varchar,
age int
);
insert into user values (1, '张三', 18);
select * from user;
输出:
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | 张三 | 18 |
+----+------+-----+
验收标准
程序不重启的情况下,可以完成建表、插入、查询。
阶段五:元数据持久化
阶段目标
让表结构保存到本地文件,程序重启后表结构仍然存在。
需要实现
1. 每张表生成一个 .meta 文件
2. 启动时加载所有 meta 文件
3. create table 后保存元数据
4. drop table 后删除元数据
5. show tables
6. desc table
文件示例
data/default/user.meta
内容:
{
"tableName": "user",
"columns": [
{"name": "id", "type": "int"},
{"name": "name", "type": "varchar"},
{"name": "age", "type": "int"}
]
}
验收标准
重启程序后执行:
show tables;
desc user;
仍然能看到之前创建的表结构。
阶段六:数据持久化与 Page 存储
阶段目标
把表中的数据保存到磁盘文件中。
需要实现
1. 表数据文件 .tbl
2. Page 固定大小存储
3. Row 序列化
4. Row 反序列化
5. insert 写入磁盘
6. select 从磁盘读取
推荐文件结构
user.tbl
内部按 Page 存储:
Page 0
Page 1
Page 2
...
每个 Page 大小:
4096 bytes
Row 示例
id:int,name:varchar,age:int
序列化成:
[是否删除][字段数量][字段1长度][字段1值][字段2长度][字段2值]...
验收标准
插入数据后关闭程序,重新启动后仍然可以查询到数据。
阶段七:where 条件查询
阶段目标
支持简单条件过滤。
需要实现
1. where id = 1
2. where age > 18
3. where age < 30
4. where name = '张三'
5. 支持 and,可选
示例
select * from user where age > 18;
条件表达式结构
class Condition {
private String column;
private String operator;
private Object value;
}
验收标准
能够根据 where 条件正确过滤数据。
阶段八:update 和 delete
阶段目标
支持数据修改和删除。
需要实现
1. update table set column = value where ...
2. delete from table where ...
3. 删除采用逻辑删除
4. 查询时跳过已删除记录
逻辑删除示例
每一行前面加一个状态位:
0 = 正常
1 = 已删除
delete 时不是真的从文件中移除,而是把状态改成已删除。
验收标准
执行:
delete from user where id = 1;
select * from user;
被删除的数据不再显示。
阶段九:B+ 树索引
阶段目标
实现数据库索引的核心原理。
需要实现
1. B+ 树节点结构
2. 叶子节点保存 key -> RowId
3. 插入索引
4. 查询索引
5. 节点分裂
6. 索引文件持久化
7. create index
8. drop index
RowId 设计
class RowId {
private int pageNo;
private int slotNo;
}
B+ 树节点示例
非叶子节点:
[10 | 20 | 30]
/ | | \
叶子节点:
[1,2,3] -> [10,11,12] -> [20,21,22]
查询过程
select * from user where age = 18;
如果 age 有索引:
1. 从 idx_user_age.idx 中查找 key=18
2. 得到 RowId
3. 根据 RowId 到 user.tbl 中读取行数据
4. 返回结果
验收标准
创建索引前后,查询结果一致,但执行计划不同。
explain select * from user where age = 18;
无索引:
FullTableScan
有索引:
IndexScan using idx_user_age
阶段十:简单查询优化器
阶段目标
让系统自动选择全表扫描或索引扫描。
需要实现
1. 生成执行计划
2. 判断 where 字段是否有索引
3. 有索引用 IndexScan
4. 无索引用 FullTableScan
5. 支持 explain 查看执行计划
示例
explain select * from user where id = 1;
输出:
Execution Plan:
IndexScan
table: user
index: primary_key
condition: id = 1
验收标准
能够通过 explain 看到当前 SQL 的执行方式。
阶段十一:事务基础版
阶段目标
实现 begin、commit、rollback。
需要实现
1. Transaction 类
2. TransactionManager
3. begin 开启事务
4. commit 提交事务
5. rollback 回滚事务
6. undo log 记录修改前数据
事务状态
enum TransactionStatus {
ACTIVE,
COMMITTED,
ROLLBACK
}
Undo Log 示例
事务ID: 1001
操作类型: UPDATE
表名: user
RowId: page=1, slot=2
修改前数据: id=1,name=张三,age=18
示例
begin;
update user set age = 20 where id = 1;
rollback;
select * from user where id = 1;
结果中 age 应该仍然是 18。
验收标准
rollback 可以撤销 insert、update、delete。
阶段十二:锁机制与并发控制
阶段目标
理解数据库并发控制。
Demo 版建议先实现表锁。
需要实现
1. 共享锁 S Lock
2. 排他锁 X Lock
3. select 加 S 锁
4. insert/update/delete 加 X 锁
5. commit/rollback 释放锁
6. 冲突时等待或直接报错
示例
事务 A:
begin;
update user set age = 20 where id = 1;
事务 B:
begin;
update user set age = 30 where id = 1;
事务 B 应该等待或提示:
table user is locked by transaction 1001
验收标准
多个事务同时修改同一张表时,不会出现数据错乱。
阶段十三:Redo Log 与崩溃恢复
阶段目标
理解数据库为什么需要日志。
需要实现
1. redo log 文件
2. commit 时写 redo log
3. 启动时扫描 redo log
4. 对已经 commit 但未刷盘的数据进行恢复
日志格式示例
TX_ID=1001
TYPE=UPDATE
TABLE=user
ROW_ID=1:2
AFTER=id=1,name=张三,age=20
STATUS=COMMIT
简化恢复规则
1. 启动时读取日志文件
2. 找到已经 commit 的事务
3. 将事务修改后的数据重新写入数据文件
4. 未 commit 的事务忽略或回滚
验收标准
模拟系统崩溃后,已提交事务的数据不丢失,未提交事务的数据不生效。
七、完整功能列表
1. SQL 功能
2. 存储功能
3. 索引功能
4. 事务功能
八、建议课程排期
版本一:4 周 Demo 版
适合课程设计或短期训练营。
版本二:8 周完整版
适合毕业设计、综合实训。
九、最终演示效果
学生最终可以运行自己的 MiniMySQL:
MiniMySQL> create table user (id int primary key, name varchar, age int);
Query OK.
MiniMySQL> insert into user values (1, '张三', 18);
1 row inserted.
MiniMySQL> insert into user values (2, '李四', 20);
1 row inserted.
MiniMySQL> select * from user;
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | 张三 | 18 |
| 2 | 李四 | 20 |
+----+------+-----+
MiniMySQL> create index idx_user_age on user(age);
Index created.
MiniMySQL> explain select * from user where age = 18;
Execution Plan: IndexScan using idx_user_age
MiniMySQL> begin;
Transaction started.
MiniMySQL> update user set age = 30 where id = 1;
1 row updated.
MiniMySQL> rollback;
Transaction rollback.
MiniMySQL> select * from user where id = 1;
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | 张三 | 18 |
+----+------+-----+
十、学生答辩可以讲的核心点
1. SQL 是如何执行的?
用户输入 SQL
-> 词法分析
-> 语法分析
-> 生成 AST
-> 生成执行计划
-> 执行器执行
-> 存储引擎读写数据
-> 返回结果
2. 数据是如何存储的?
表结构保存到 meta 文件
表数据保存到 tbl 文件
tbl 文件按 Page 组织
Page 中保存多条 Row
Row 通过序列化写入磁盘
3. 索引为什么快?
无索引:需要扫描整张表
有索引:通过 B+ 树快速定位 RowId
再根据 RowId 读取具体数据
4. 事务如何回滚?
修改数据前先记录 Undo Log
rollback 时根据 Undo Log 恢复旧数据
commit 时清理或标记事务完成
5. 数据库崩溃后如何恢复?
commit 前写 Redo Log
系统重启时扫描日志
已经提交的事务重新应用
未提交的事务回滚或忽略
十一、项目难度分层
基础版
适合大二、大三学生。
实现:
SQL 解析
内存数据库
文件持久化
基础 select / insert / update / delete
进阶版
适合课程设计、实训项目。
实现:
Page 存储
Buffer Pool
B+ 树索引
Explain 执行计划
事务 rollback
高阶版
适合毕设或竞赛项目。
实现:
Redo Log
崩溃恢复
表锁/行锁
简单查询优化器
可视化执行过程
Web 控制台
十二、推荐最终项目亮点
为了让这个项目更适合教学和答辩,可以额外做一个可视化控制台。
Web 控制台功能
1. SQL 输入框
2. 查询结果表格展示
3. 表结构展示
4. 执行计划展示
5. B+ 树索引结构可视化
6. Page 文件结构可视化
7. 事务日志展示
8. Buffer Pool 缓存页展示
十三、最终交付物
学生最终需要提交:
1. MiniMySQL 项目源码
2. 项目说明文档
3. 数据库存储结构说明
4. SQL 解析流程说明
5. B+ 树索引实现说明
6. 事务与日志实现说明
7. 测试用例文档
8. 演示视频或答辩 PPT
十四、项目核心价值
学生完成后,可以真正理解:
SQL 为什么不是直接执行字符串
MySQL 为什么需要索引
B+ 树为什么适合数据库
数据库为什么按 Page 存储
事务为什么需要 Undo Log
崩溃恢复为什么需要 Redo Log
为什么 update/delete 不能只是简单改文件
为什么数据库并发需要锁
为什么 explain 能看到执行计划
这个项目做完后,放在简历上可以写成:
MiniMySQL 数据库内核教学项目
基于 Java 从 0 实现了一个简化版关系型数据库,支持 SQL 解析、表结构管理、数据持久化、Page 存储、B+ 树索引、执行计划选择、事务提交与回滚、Undo Log、Redo Log 以及简单锁机制。通过该项目深入理解了 MySQL 的 SQL 执行流程、存储引擎、索引结构和事务原理。