C++: 实战:简易数据库

最后更新:2026-08-26

第51课我们做了通讯录系统。

现在,我们要做第二个综合实战项目——简易数据库。

这个项目会用到C++的很多高级特性,是检验学习成果的试金石。


1. 项目需求

(1) 1.1 功能需求

功能 说明
CREATE TABLE 创建表
INSERT 插入数据
SELECT 查询数据
WHERE 条件过滤
索引 加速查询
事务 保证ACID

(2) 1.2 简化设计

由于是教学项目,我们做简化版



2. 表结构设计

(1) 2.1 列定义

▶ 示例 2:代码示例(难度⭐)

CPP
#include <iostream>
#include <string>
#include <variant>
#include <vector>

// 列定义
struct Column {
 std::string name;
 enum Type { INT, STRING } type;
};

// 值类型(用variant存储不同类型)
using Value = std::variant<int, std::string>;

// 行(一行数据)
using Row = std::vectorValue;

// 表
class Table {
private:
 std::string name;
 std::vectorColumn columns;
 std::vectorRow rows;

public:
 Table(const std::string& name, const std::vectorColumn& columns)
 : name(name), columns(columns) {}
 
 // 插入一行
 void insert(const Row& row) {
 if (row.size() != columns.size()) {
 std::cerr << "列数不匹配" << std::endl;
 return;
 }
 rows.push_back(row);
 }
 
 // 查询(简化版:返回所有行)
 std::vectorRow select() {
 return rows;
 }
 
 // 显示表结构
 void describe() const {
 std::cout << "表名:" << name << std::endl;
 std::cout << "列:" << std::endl;
 for (const auto& col : columns) {
 std::cout << " " << col.name << " (";
 if (col.type == Column::INT) {
 std::cout << "INT";
 } else {
 std::cout << "STRING";
 }
 std::cout << ")" << std::endl;
 }
 }
};
▶ 试一试

输出:

TEXT 📖 仅展示
表名:
列:
  (
INT
STRING
)


3. 查询实现

(1) 3.1 WHERE子句

CPP
// 谓词函数(用于WHERE)
using Predicate = std::function<bool(const Row&)>;

// 带条件的查询
std::vectorRow selectWhere(Predicate pred) {
 std::vectorRow result;
 for (const auto& row : rows) {
 if (pred(row)) {
 result.push_back(row);
 }
 }
 return result;
}

// 示例:查找age > 18的行
auto predicate = (const Row& row) {
 int age = std::getint(row[1]); // 假设第2列是age
 return age > 18;
};

auto result = table.selectWhere(predicate);


4. 索引实现

(1) 4.1 简单索引

CPP
#include <map>

// 索引(简化版:只对int类型建索引)
class Index {
private:
 std::map<int, std::vector<int>> index; // 值 -> 行号列表

public:
 void build(const std::vectorRow& rows, int colIndex) {
 index.clear();
 for (int i = 0; i < rows.size(); i++) {
 int key = std::getint(rows[i][colIndex]);
 index[key].push_back(i);
 }
 }
 
 std::vector<int> lookup(int key) {
 auto it = index.find(key);
 if (it != index.end()) {
 return it->second;
 }
 return {};
 }
};


5. 事务支持

(1) 5.1 简化事务

CPP
#include <stack>

class Transaction {
private:
 std::stack<std::vectorRow> undoStack;

public:
 // 开始事务(保存当前状态)
 void begin(Table& table) {
 undoStack.push(table.rows);
 }
 
 // 提交(清空undo栈)
 void commit() {
 while (!undoStack.empty()) {
 undoStack.pop();
 }
 }
 
 // 回滚(恢复上一个状态)
 void rollback(Table& table) {
 if (!undoStack.empty()) {
 table.rows = undoStack.top();
 undoStack.pop();
 }
 }
};


6. 完整示例

▶ 示例 1:使用简易数据库(难度⭐⭐⭐)

CPP
int main() {
 // 创建表
 Table t("users", {{"name", Column::STRING}, {"age", Column::INT}});
 
 // 插入数据
 t.insert({"Alice", 25});
 t.insert({"Bob", 30});
 t.insert({"Charlie", 20});
 
 // 查询所有
 auto rows = t.select();
 std::cout << "所有用户:" << std::endl;
 for (const auto& row : rows) {
 std::cout << std::getstd::string(row[0]) << ", "
 << std::getint(row[1]) << std::endl;
 }
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
所有用户:
, 


7. 扩展方向

(1) 7.1 功能扩展

功能 难度 说明
持久化 ⭐⭐ 保存到文件
JOIN ⭐⭐⭐⭐ 多表连接
SQL解析器 ⭐⭐⭐⭐⭐ 解析SQL语句
并发控制 ⭐⭐⭐⭐ 多线程安全


8. ❓ 练习

(1) 基础练习(难度⭐⭐)

给数据库添加DELETE功能。

(2) 进阶练习(难度⭐⭐⭐)

给数据库添加UPDATE功能。

(3) 挑战练习(难度⭐⭐⭐⭐)

实现简单的SQL解析器,支持SELECT * FROM table WHERE age > 18


▶ 示例 3:数据库表结构定义(难度⭐)

CPP
#include <iostream>
#include <string>
#include <vector>
#include <variant>

// 值类型(支持多种数据类型)
using Value = std::variant<int, std::string, double>;

// 一行数据
struct Row {
    int id;
    Value name;
    Value age;
    Value score;

    void display() const {
        std::cout << "ID: " << id << std::endl;
        std::cout << "Name: " << std::get<std::string>(name) << std::endl;
        std::cout << "Age: " << std::get<int>(age) << std::endl;
        std::cout << "Score: " << std::get<double>(score) << std::endl;
    }
};

int main() {
    Row r = {1, std::string("Alice"), 20, 95.5};
    r.display();
    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
ID: 
Name: 
Age: 
Score: 

❓ 常见问题

Q map的查找效率有多快?
A map内部是红黑树实现,查找、插入、删除都是O(log n)时间复杂度。对于100万条数据,最坏情况下只需约20次比较。
Q 为什么用CSV存储文件?
A CSV格式简单、可读性好、可以用Excel直接打开查看。JSON格式支持嵌套结构但解析稍微复杂。生产环境推荐用SQLite。
Q 如何防止SQL注入?
A 本项目是简易实现,实际生产环境一定要使用参数化查询或预处理语句。永远不要直接拼接用户输入的字符串到SQL语句中。

📖 小节

知识点 应用
variant 存储不同类型的值
vectorRow 存储表数据
map 实现索引
函数对象 实现WHERE谓词

📝 作业

  1. 基础题 (Difficulty ⭐): 运行数据库程序,创建一张"学生表"(字段:学号、姓名、年龄、成绩),插入3条记录,查询所有记录。

  2. 进阶题 (Difficulty ⭐⭐): 增加"排序查询"功能——支持 SELECT * FROM table ORDER BY 年龄。提示:用 std::sort + lambda 表达式按指定字段排序。

  3. 挑战题 (Difficulty ⭐⭐⭐): 实现"多表关联"——创建两张表(学生表、成绩表),支持 SELECT 学生.姓名, 成绩.分数 FROM 学生 JOIN 成绩 ON 学生.学号 = 成绩.学号。需要设计 JOIN 逻辑和结果合并。


下一课:课程总结与进阶路线(#53)

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏