SQLite的优雅设计: 展示了即使是极其复杂的项目,也可以保持简单易用
将「单文件头文件库」的概念发挥到极致------同一个被称作 amalgamated source 的单文件,包含了将近 30 万行代码,但使用起来就像用一个简单的小库一样。
SQLite
SQLite 是一个实现 SQL 数据库引擎的库,从手机应用到浏览器、从桌面软件到服务器,几乎所有设备都在使用它。按使用量计算,它是世界上使用最广泛的数据库
安装与使用(零依赖)
1. 获取源码
访问 SQLite 下载页面,下载 amalgamated sources(合并后的源码包)。
bash
wget https://www.sqlite.org/xxxxx.zip
unzip sqlite-autoconf-xxxxxxx.zip
下载的压缩包包含 4 个文件:
| 文件 | 说明 |
|---|---|
sqlite3.c |
核心库文件,约 30 万行代码 |
sqlite3.h |
头文件,约 1.4 万行代码 |
sqlite3ext.h |
扩展头文件,约 700 行代码(用于编写插件) |
shell.c |
命令行工具实现,约 4 万行代码 |
2. 示例
c
#include <stdio.h>
#include "sqlite3.h"
int main(int argc, char **argv) {
sqlite3 *db;
char *err_msg = 0;
// 打开数据库连接
int rc = sqlite3_open("test.db", &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
// 执行 SQL 语句
rc = sqlite3_exec(db, "CREATE TABLE Users (id INTEGER PRIMARY KEY, name TEXT)", 0, 0, &err_msg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return 1;
}
sqlite3_close(db);
return 0;
}
整个核心使用流程只有三步:
sqlite3_open()--- 打开数据库连接sqlite3_exec()--- 执行 SQL 查询sqlite3_close()--- 关闭连接
编译方式
方式一:静态编译
将 SQLite 直接编译进可执行文件:
bash
gcc -o main main.c sqlite3.c -lpthread -ldl
编译参数说明:
-lpthread--- 线程支持-ldl--- 动态链接支持- 编译时间稍长(SQLite 较大),但最终产物是单个可执行文件,部署简单
方式二:动态编译
先单独编译动态库,再链接:
bash
# 编译动态库
gcc -shared -fPIC -o libsqlite3.so sqlite3.c
# 链接动态库
gcc -o main main.c -L. -lsqlite3
# 运行(需要指定库路径)
LD_LIBRARY_PATH=. ./main
使用 -L. 指定在当前目录查找库,避免链接到系统安装的 SQLite。
API 设计
核心 API 精简
SQLite 的 API 表面看起来只有 10 个核心函数,掌握这些就能完成 90% 的日常工作:
| API 函数 | 用途 |
|---|---|
sqlite3_open() |
打开/创建数据库 |
sqlite3_close() |
关闭连接 |
sqlite3_exec() |
执行 SQL 语句 |
sqlite3_prepare() |
预处理语句 |
sqlite3_step() |
执行预处理语句 |
sqlite3_finalize() |
销毁预处理语句 |
sqlite3_bind_*() |
绑定参数 |
sqlite3_column_*() |
读取结果列 |
sqlite3_errmsg() |
获取错误信息 |
sqlite3_close_v2() |
改进版关闭函数 |
虽然 SQLite 实际上有 225+ 个 API ,但文档只展示你 90% 时间会用到的核心部分,让新手不会「知识淹没」。
API 版本管理
c
sqlite3_prepare() // 旧版,已废弃
sqlite3_prepare_v2() // 当前推荐版本
sqlite3_prepare_v3() // 最新版本
向后兼容性原则:旧 API 仍然可用,不破坏用户现有代码 Never break user space
库设计原则
1. 默认安装方式应该是「下载即用」
- 下载压缩包
- 解压
- 包含头文件
- 用普通编译器编译
任何语言、任何项目都不应该强制要求使用特定的构建系统。 即使语言有 npm、pip、cargo 等包管理器,也应该保留「拖拽添加」的能力。这会促使开发者设计更轻量的依赖。
2. 文档要「漏斗导向成功」
不要一开始就把所有 API 堆在用户面前:
- 先展示核心功能(10 个函数)
- 进阶功能放在需要时再查阅
- 让用户从「一无所知」到「能用」的时间最短
3. 尊重向后兼容性
- 需要新接口时,命名 V2/V3 而不是废弃旧接口
- 旧代码在新版本下仍能运行
相关:
Neovim 打开 30 万行文件同样流畅,现代编辑器的性能足以处理大文件
OpenSSL 同样采用 amalgamated source 方式
SQLite 用一个 30 万行的单文件 证明了:
- 复杂性可以被封装
- 简单性可以被保持
- 向后兼容性是可以做到的