提到数据库,很多人第一反应是 MySQL、PostgreSQL 这类需要独立服务进程的「大家伙」,但在数以十亿计的手机、浏览器和桌面应用里,真正扛住日常读写的是 SQLite——一个零配置、无服务端、整个数据库就是单个文件的嵌入式数据库。这篇文章从安装上手讲到 WAL 并发配置与生产落地实践,帮你判断什么场景该放心用它、什么场景必须换重型数据库。
SQLite 是什么:一个文件就是一座数据库
SQLite 不是 MySQL 的简化版,而是一种完全不同的架构思路:它把整个数据库(表、索引、数据)封装进一个普通的磁盘文件,由嵌入在应用进程内的 C 语言库直接读写,没有网络监听、没有用户权限体系、没有任何需要提前规划的配置文件。你在应用里调用一个函数,就是一次完整的数据库访问。
这个设计带来三个直接好处。第一,零运维:不需要安装服务、不需要配置账号密码,复制文件就是备份。第二,极低延迟:读写走函数调用而非网络往返,单机小查询通常在微秒级完成。第三,极强的可移植性:数据库文件跨平台通用,从 ARM 单板机到 x86 服务器都能直接打开。世界上最大的部署规模也印证了它的可靠性——每一台 iPhone、每一款主流浏览器里都跑着 SQLite。
五分钟上手:从安装到第一条 SQL
SQLite 的命令行工具 sqlite3 是最直观的入门方式,建表、插入、查询一条龙跑通不超过五分钟:
# Debian/Ubuntu
sudo apt install sqlite3
# macOS 自带,也可 brew upgrade sqlite
# 创建并打开数据库
sqlite3 demo.db
-- 建表与插入
CREATE TABLE user (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at TEXT DEFAULT (datetime('now'))
);
INSERT INTO user (name, email) VALUES ('张三', 'zhang@example.com');
-- 查询与格式化输出
.mode column
.headers on
SELECT * FROM user;
注意 id 列声明为 INTEGER PRIMARY KEY,它是 rowid 的别名,相当于自带的自增主键,不需要 AUTO_INCREMENT 这类额外语法。datetime(’now’) 是 SQLite 内置的 UTC 时间函数,默认时间戳落库就用它。
在 Python 中使用 sqlite3:标准库就够
Python 标准库内置 sqlite3 模块,不用装任何第三方包。唯一要养成习惯的是:外键约束默认是关闭的,每个连接都要手动执行 PRAGMA foreign_keys = ON;参数占位符用问号加元组传参,杜绝字符串拼接带来的 SQL 注入风险:
import sqlite3
# 自动开启外键约束(SQLite 默认关闭)
conn = sqlite3.connect('demo.db')
conn.execute('PRAGMA foreign_keys = ON')
conn.row_factory = sqlite3.Row # 查询结果可按列名取值
cur = conn.cursor()
cur.execute('INSERT INTO user (name, email) VALUES (?, ?)', ('李四', 'li@example.com'))
conn.commit()
rows = cur.execute(
'SELECT id, name FROM user WHERE created_at >= ?',
('2026-01-01',)
).fetchall()
for r in rows:
print(r['id'], r['name'])
conn.close()
这里全部使用参数化查询,占位符 ? 由驱动负责转义。如果是 Web 后端框架,Django ORM 和 SQLAlchemy 都把 SQLite 列为一等公民,本地开发环境几乎零成本切换。
数据类型与类型亲和性
SQLite 只提供五种存储类型(NULL、INTEGER、REAL、TEXT、BLOB),但你建表时写的 VARCHAR(255)、DOUBLE 等类型名并不会报错——它靠「类型亲和性」规则把常见类型名映射到五种存储类型上,兼容从 MySQL 迁移来的建表语句:
| 你写的类型 | 亲和性 | 实际存储行为 |
|---|---|---|
| INT / INTEGER / BIGINT | INTEGER | 整数直接存,主键推荐用 INTEGER PRIMARY KEY |
| TEXT / VARCHAR / CLOB | TEXT | 按文本存,长度声明仅作提示不强制截断 |
| REAL / DOUBLE / FLOAT | REAL | 8 字节 IEEE 浮点数 |
| BLOB / 无类型 | BLOB | 原始二进制,图片、序列化数据存这里 |
| DATE / DATETIME | NUMERIC | 推荐直接存 TEXT 格式时间戳或整数 epoch |
这套机制的好处是建表语句宽松,代价是约束偏弱:想严格控制取值范围,要用 CHECK 约束补上。这也是它和 MySQL、PostgreSQL 在工程风格上的核心差异之一。
WAL 模式:让读写并发不再互相阻塞
SQLite 默认的回滚日志(journal)模式下,写事务会阻塞读,很多「SQLite 不支持并发」的印象其实源于没有切换到 WAL(Write-Ahead Logging)模式。WAL 把写操作先追加到独立的 -wal 文件,读操作继续走主库文件,读写互不阻塞,性能和并发能力都会显著提升。建库时执行一次即可持久生效:
-- 切换 WAL 模式(持久设置,只需执行一次)
PRAGMA journal_mode = WAL;
-- 推荐的基础参数组合
PRAGMA synchronous = NORMAL; -- WAL 下 NORMAL 已足够安全
PRAGMA busy_timeout = 5000; -- 写锁等待 5 秒再报错
PRAGMA foreign_keys = ON; -- 每个连接都要开启
PRAGMA cache_size = -64000; -- 64MB 页缓存
-- 检查当前模式
PRAGMA journal_mode;
即便开了 WAL,同一时刻仍然只允许一个写事务,多进程高频写入同一库文件依旧会排队。经验法则是:写并发高就上消息队列串行化,或直接换客户端/服务端数据库;读多写少(内容站、配置中心、移动端本地存储)则 WAL 模式下的 SQLite 足以应对每秒数千次查询。
SQLite 与 MySQL/PostgreSQL 怎么选
选型的核心不是性能跑分(真要量化可以看数据库压测实战:用 sysbench 与 pgbench 量化性能的思路照搬给 SQLite 做基准),而是部署形态与并发模型:
| 维度 | SQLite | MySQL / PostgreSQL |
|---|---|---|
| 部署形态 | 嵌入进程,零服务 | 独立服务进程 + 网络监听 |
| 并发写 | 单写者串行 | 多连接并发写,行级锁 |
| 网络访问 | 不支持 | 原生支持分布式客户端 |
| 用户权限 | 无(靠文件权限) | 完整的账号/角色/权限体系 |
| 数据库体积 | 单文件,MB 级起步 | 数据目录,GB 级常见 |
| 典型场景 | 移动端、桌面应用、边缘设备、本地缓存 | Web 后端、多服务共享、高并发业务 |
一条实用的判断线:数据只有一个进程读写,或以读为主——选 SQLite;多个服务实例要共享同一份数据、写入并发高、需要细粒度权限——上 MySQL 或 PostgreSQL,并配合MySQL EXPLAIN 执行计划做慢查询治理。
生产环境落地的六条实践
1. 备份用在线 API 而非直接拷贝
WAL 模式下直接复制 db 文件可能拿到缺少最新 -wal 内容的不一致快照。正确姿势是调用 VACUUM INTO ’backup.db’ 或 Python 的 conn.backup() 接口,拿到的永远是事务一致的全量副本。
2. 主键与索引纪律
每张表显式声明 INTEGER PRIMARY KEY 或 UNIQUE 索引,避免全表扫描;WHERE、ORDER BY 涉及的列优先建索引。索引设计方法论可以参考数据库设计规范实战:范式、索引与命名约定,原则完全通用。
3. 事务批量化
SQLite 单条 COMMIT 的 fsync 开销可观。批量导入时用 BEGIN 包住上千条 INSERT 再一次性 COMMIT,写入速度可以从每秒几十条跃升到几十万条。
4. 慎用网络文件系统
把数据库文件放在 NFS、Samba 等网络挂载上,文件锁语义不可靠,可能导致损坏。SQLite 官方明确不建议这种部署,多机共享请改用真正的服务端数据库。
5. 控制单库体积
单库几十 GB 依然能工作,但 VACUUM、备份的维护窗口会明显变长。建议按业务拆库(每个业务域一个文件),这也符合嵌入式数据库「小而专」的定位。
6. 监控三个关键 PRAGMA
用 PRAGMA integrity_check 定期做完整性校验;PRAGMA wal_checkpoint(TRUNCATE) 控制 WAL 文件膨胀;PRAGMA page_count / freelist_count 观察空间水位。
现代应用里的 SQLite:从客户端到边缘计算
最近几年 SQLite 迎来第二春。浏览器端有 sql.js/WASM 让 SQL 直接跑在前端;桌面应用(Electron、Tauri)普遍拿它做本地状态存储;边缘计算与 IoT 网关用它替代文件日志;甚至出现了 LiteFS、Turso 这类把 SQLite 复制到云端的项目,试图以「单文件 + 复制」的形态对抗重型数据库。移动端领域它更是绝对霸主:iOS 的 Core Data 和 Android 的 Room 底层都是 SQLite。
全文检索方向同样值得关注:SQLite 内置 FTS5 虚拟表,建一个全文索引只需一行 CREATE VIRTUAL TABLE … USING fts5(…),能在单文件内实现类似Elasticsearch 倒排索引全文搜索的基本能力,非常适合小型站内搜索或笔记应用的本地检索。
总结
SQLite 的正确打开方式是认清它的定位:它不是「低配 MySQL」,而是嵌入式场景下的最优解。记住三条主线——单文件零运维是它的护城河,WAL 模式是并发能力的开关,多机共享写是它的边界。把握住这三点,从移动端本地存储到边缘网关再到小型 Web 服务,SQLite 都能以最低的运维成本交付可靠的数据库能力;而当业务真正长出高并发写与多服务共享的需求时,再平滑迁移到 MySQL/PostgreSQL 也不迟。




