SQLite 与 node:sqlite
在 Deno 中使用 node:sqlite 与兼容库,覆盖选型、最小权限与 WAL/备份边界
Deno 自 v2.2 起在 Node 兼容层中提供 node:sqlite,官方 Node API 文档将其列为完整支持模块。上游 Node.js 中该模块加入于 v22.5.0,截至 2026-08-03 上游稳定性标注为 1.2(release candidate),正式稳定前仍可能有小幅 API 调整,升级 Deno 时应复查。
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("./data/app.db");
db.exec(`
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL
) STRICT;
`);
const insert = db.prepare("INSERT INTO posts (title) VALUES (?)");
insert.run("Hello Deno");
const rows = db.prepare("SELECT id, title FROM posts").all();
DatabaseSync 的 API 全部同步执行,适合脚本、CLI 和单写者服务;不要把同步长查询放进高并发请求路径。
备选库
| 库 | 形态 | 注意 |
|---|---|---|
node:sqlite | 内置 Node 兼容模块 | 无需安装依赖;上游仍是 release candidate |
jsr:@db/sqlite | FFI 加载预编译原生库 | 官方 README 要求 --allow-ffi、--allow-env,且需要网络与文件权限下载缓存原生库 |
npm:better-sqlite3 | Node 原生 addon | 依赖 Deno 对原生 addon 的支持,使用前按所用 Deno 版本核对 |
FFI 与原生 addon 加载机器码,JavaScript 层权限无法约束其系统调用;选型时把这一点计入信任边界。纯 WASM 方案(如 npm:sql.js)不触碰 FFI,但数据库在内存中、持久化要自己处理。
何时选 SQLite
- 单机服务、CLI 工具、桌面/边缘单实例应用。
- 测试与本地开发:用
:memory:或临时文件隔离每个测试。 - 读多写少的嵌入式场景,配合 WAL 让读写并发。
- 多区域/边缘副本属于 LiteFS、libsql 一类方案的领域,超出
node:sqlite范围,选型时单独评估。
最小权限
deno run --allow-read=./data --allow-write=./data src/main.ts
- WAL 模式会创建
app.db-wal与app.db-shm旁车文件,只授权精确到app.db会在 checkpoint 或首次写入时失败;授权目录,或把三个文件全部列出。 - 只读工具用
new DatabaseSync(path, { readOnly: true })配合--allow-read,不授写权限。 jsr:@db/sqlite等 FFI 方案本质上需要接近-A的信任级别,不要用权限收窄自我安慰。
WAL、备份与并发写边界
- SQLite 是单写者:WAL 下读写可并发,写与写仍互斥;写事务要短,
busy_timeout决定锁竞争时等待多久,超时抛SQLITE_BUSY。 - 多进程打开同一文件可行,但写吞吐不会因此提高;网络文件系统(NFS 等)上不要使用 SQLite。
- 备份前先做
PRAGMA wal_checkpoint(TRUNCATE),否则直接拷贝主文件会丢失仍在 WAL 中的提交;或使用 SQLite 官方 CLI 的.backup。 - 上游
node:sqlite自 Node v23.8.0 / v22.16.0 起提供sqlite.backup(),Deno 各版本的支持情况以所用版本实测为准。 - migration 与 PostgreSQL 同理:作为发布步骤执行,应用启动时自动改 schema 在多实例下会放大并发风险。
官方参考:Deno Node API 支持列表、Node.js node:sqlite 文档、jsr:@db/sqlite、SQLite WAL 模式。