编程闭关教程 · 系列 08–20 · 编制日期 2026-10-14

SQLite3 专题:把单文件数据库用成默认之选

数据库四件套 ④。SQLite 不是"缩小版的 MySQL",而是一种完全不同的架构:一个文件就是整个数据库,没有守护进程,没有端口,没有账号体系。本模块讲清它的边界(什么场景封神、什么场景绝不能用)、WAL 并发模型、Go 侧纯驱动集成(modernc / glebarez,免 CGO 交叉编译一把过)、热备份与运维,以及 1GB 服务器上如何用它替代重型库。工作台(模块 11)默认数据库就是它——里程碑 M1 直接跑在 SQLite 上。
本模块承诺读完并照做:你能在 Windows 本机与 1GB Linux 服务器上,用 Go 纯驱动(无 CGO、免 gcc)把 SQLite 配成 WAL + busy_timeout + 外键的生产形态,能做一次 VACUUM INTO 热备份,并且——更重要的——能一眼判断"这个项目该不该用 SQLite"。
3.53.4
锁定 SQLite 版本(2026-07-24)
单文件
一个 .db 文件 = 整个库
0
守护进程 / 端口 / 账号
免 CGO
modernc 纯 Go,交叉编译一把过
1 写者
单写者语义(WAL 也不例外)
版本唯一事实来源:全系列锁定版本清单(09 模块 §4)。本模块涉及工作台代码处一律以工作台契约(Go + Gin + GORM,DB_DRIVER=sqlite)为准,不新增端点。
08 总纲 09 环境·版本 10 Go 内核 11 工作台 12 Vue3 13 Flutter 14 Python 15 C/C++ 16 MySQL 17 PostgreSQL 18 Redis 19 SQLite3 20 部署
本页目录
  1. 版本与定位:什么时候用、什么时候绝不能用
  2. 获得与安装:Windows 本机 + Linux 服务器
  3. 核心概念(最小必要)
  4. SQL 速查:DDL / DML / PRAGMA / 备份命令
  5. Go 集成①:modernc 纯驱动(database/sql)
  6. Go 集成②:glebarez + GORM(工作台默认配置)
  7. 1GB 服务器上的选型决策表
  8. 常见场景与最佳实践:备份 / 恢复 / 并发 / 索引
  9. 常见报错对照表(12 条)
  10. 本模块验收
  11. 来源表
01

版本与定位:什么时候用、什么时候绝不能用

先把边界划死,再学用法。SQLite 被误用(拿它扛高并发写)和被埋没(明明该用却上了 MySQL)一样常见。

1.1 锁定版本

组件锁定版本发布日期说明
SQLite 引擎3.53.42026-07-24官方 amalgamation 稳定版;Go 驱动内嵌的就是这份 C 源码的翻译/绑定,不用单独装引擎
modernc.org/sqlitev1.60.12026-09-29纯 Go database/sql 驱动(cc 翻译的 SQLite),免 CGO
glebarez/sqlitev1.11.02024-03-14包装 modernc 的 GORM 驱动,工作台默认 DB_DRIVER=sqlite 走它
mattn/go-sqlite3v1.14.52(备选)2026-09-05CGO 驱动,性能上限略高但交叉编译麻烦;本教程场景不首选
GORMv1.31.2(v2 API 线)2026-06-22工作台 ORM;注意模块 tag 是 v1.x 序列、API 是 v2

版本纪律:以上版本全部来自全系列锁定版本清单(09 模块 §4),照抄即可,不要自己去"更新到最新"。Go 侧的 SQLite 是随驱动二进制一起发布的——你锁了 modernc v1.60.1,就等于锁了它内嵌的那份 SQLite 引擎版本,服务器上不需要再装任何 sqlite3 软件包。

1.2 适用边界(对照 08 §8.1 四件套分工表)

SQLite 封神的场景

① 个人工作台 / 本地工具:单机、单用户或极小并发,零运维。② 原型与 MVP:省去装库、建库、配账号的全部前置。③ 1GB 低配服务器替代重型库:内存只有 1GB 时,MySQL/PG 常驻进程就要吃掉几百 MB,SQLite 零常驻。④ 嵌入式 / 客户端本地存储:桌面应用、CLI 工具的"数据库"就是一个文件。⑤ 读多写极少的内部系统(后台、报表、内容站)。

SQLite 绝不能扛的场景

① 高并发写:全库同一时刻只能有一个写事务(WAL 也只是让读写不互斥,写与写仍互斥)。② 多写者:多台机器/多个进程同时高频写同一个 .db 文件。③ 写并发上来后的网站主力库——那是 MySQL(16 模块)的位置。④ 需要行级锁、复杂复制、权限体系的多租户业务。一句话:SQLite 是"单写者单机"架构,不是"小型网络数据库"。
与 08 §8.1 分工的对应:SQLite = 单机/原型/工作台默认;MySQL = 客户网站/业务主力;PostgreSQL = 复杂数据/合规;Redis = 缓存与队列。你的 1GB 服务器上跑工作台这类低并发工具,SQLite 就是默认答案;哪天业务出现"多用户同时写"的特征,再按 16 模块切 MySQL——工作台契约本来就预留了 DB_DRIVER=mysql 开关。
02

获得与安装:Windows 本机 + Linux 服务器

SQLite 的"安装"比任何数据库都简单:它不是服务,没有 systemd unit,没有监听端口。你只需要两样东西之一——命令行工具(手动玩库用),或 Go 驱动(程序用,内嵌引擎)。

2.1 Windows 本机

  1. 方式 A(推荐,手动操作库时用):去 SQLite 官方下载页拿预编译的命令行工具 sqlite3.exe(zip 包,解压即用),放进一个已加入 PATH 的目录(如 C:\Tools\sqlite3\)。不需要安装程序、不需要管理员权限。
  2. 方式 B(程序开发的默认形态):什么都不装。Go 用 modernc 驱动时,SQLite 引擎已经编译进你的二进制,程序运行时自己打开一个 .db 文件即可。工作台走的就是这条路。
  3. 验证(PowerShell):
    # 方式 A:验证命令行工具
    sqlite3 -version
    # 预期输出类似:3.53.4 ... x64
    
    sqlite3 D:\data\workbench.db
    # 进入交互提示符后:
    sqlite> SELECT sqlite_version();
    # 预期:3.53.4
    sqlite> .quit

2.2 Linux 服务器(1GB)

  1. 推荐形态:不装任何东西。Windows 本机交叉编译出的 Go 单二进制(GOOS=linux GOARCH=amd64,modernc 纯 Go 驱动)拷到服务器即可运行,引擎内嵌,不需要 gcc、不需要 apt install。这正是 1GB 机器的最大红利:省掉编译工具链,也省掉数据库常驻内存。
  2. 仅当你要在服务器上手动排查库文件,才装命令行工具:
    # Debian/Ubuntu(一次性,仅排查用)
    sudo apt update && sudo apt install -y sqlite3
    sqlite3 --version
    # 预期:3.53.x(发行版打包版本可能略旧,不影响程序,程序用的是驱动内嵌版本)

关键认知:服务器上 apt install sqlite3 装的命令行工具,和你程序实际使用的 SQLite 引擎是两份独立的代码——前者只是给你手敲 SQL 排查用;后者是 Go 二进制内嵌的那一份。不要以为"服务器装了 sqlite3 包"就等于"程序用的是系统版本"。

03

核心概念(最小必要)

只讲让你"不踩坑"的那部分理论。教科书式的 B 树细节、页结构演进,等阶段四再补。

3.1 单文件与无服务器架构

3.2 类型亲和(type affinity)——与 MySQL/PG 的思维差异

SQLite 是动态类型:列声明的类型只是"亲和倾向",不是硬约束。你声明 age INTEGER,真塞进去一个字符串它也存得下(按亲和规则做转换尝试)。所以:数据合法性靠你的程序(和 GORM)把关,不要指望数据库拦你。建表时仍要写合理的类型(INTEGER / TEXT / REAL / BLOB),这是为了走对索引亲和,不是为了强校验。

3.3 WAL 模式:本教程的默认 journal 模式

模式行为取舍
delete(默认)写操作前回滚日志覆盖整个库文件;读写互斥兼容性最好;但读时写会被堵、写时读会被堵,并发差
WAL(本教程采用)写先追加到 -wal 文件,读走主库;读写不互斥读并发明显更好;写仍全局单写者;崩溃后可从 WAL 恢复

记住这句:WAL 提升的是"读并发",不是"写并发"。两个写事务仍然只能排队进行。看到 database is locked 时,先怀疑是不是有写事务没提交/没回滚,而不是"我没开 WAL"。

3.4 必记的 PRAGMA(连接建立后立刻设置)

PRAGMA本教程取值作用
journal_modeWAL开启预写日志,读写不互斥(见 3.3)
busy_timeout5000(毫秒)遇到锁时等待最多 5 秒而不是立刻报 SQLITE_BUSY——低配服务器消峰的关键
foreign_keysONSQLite 默认不启用外键约束!必须每条连接显式打开,否则 REFERENCES 形同虚设
synchronousNORMALWAL 下 NORMAL 是官方推荐:断电最多损坏最后一次事务,崩溃不丢库;比 FULL 快很多

三条连接级铁律:① 每个新连接都要执行这组 PRAGMA(WAL 是库级持久的,但 busy_timeout / foreign_keys 是连接级,连接池里每个连接都得设到);② 外键不开 = 你写的 REFERENCES 全是摆设;③ busy_timeout 不设 = 偶发锁直接报错给用户。

3.5 事务与单写者语义;VACUUM

04

SQL 速查:DDL / DML / PRAGMA / 备份命令

语法与 MySQL 高度相似(你有 ThinkPHP 底子),只列差异点和高频命令。

4.1 建表与 CRUD(对照工作台 Task 模型)

-- DDL:建表(注意类型亲和,INTEGER PRIMARY KEY = 自增主键)
CREATE TABLE IF NOT EXISTS tasks (
  id         INTEGER PRIMARY KEY AUTOINCREMENT,
  title      TEXT    NOT NULL,
  note       TEXT    DEFAULT '',
  done       INTEGER NOT NULL DEFAULT 0,   -- SQLite 无原生 BOOLEAN,用 0/1
  created_at  TEXT    NOT NULL,              -- 时间用 TEXT 存 RFC3339,Go 侧 time.Time 自动映射
  updated_at  TEXT    NOT NULL
);

-- DML
INSERT INTO tasks (title, note, done, created_at, updated_at)
  VALUES ('写周报', '周五前', 0, '2026-10-14T09:00:00+08:00', '2026-10-14T09:00:00+08:00');
SELECT id, title, done FROM tasks WHERE done = 0 ORDER BY id DESC LIMIT 20;
UPDATE tasks SET done = 1, updated_at = '2026-10-14T10:00:00+08:00' WHERE id = 1;
DELETE FROM tasks WHERE id = 1;

-- 事务(写事务尽量短)
BEGIN IMMEDIATE;
  UPDATE tasks SET done = 1 WHERE id = 1;
  UPDATE tasks SET done = 1 WHERE id = 2;
COMMIT;   -- 出错就 ROLLBACK;

4.2 高频 PRAGMA 与诊断命令

PRAGMA journal_mode=WAL;        -- 库级,执行一次永久生效
PRAGMA busy_timeout=5000;       -- 连接级,每个连接都要设
PRAGMA foreign_keys=ON;         -- 连接级,默认 OFF!
PRAGMA synchronous=NORMAL;

PRAGMA integrity_check;          -- 体检:返回 ok 即库文件完好
PRAGMA wal_checkpoint;           -- 手动把 WAL 合并回主库
.tables                          -- 命令行点命令:列出所有表
.schema tasks                    -- 命令行点命令:看建表语句

4.3 备份 / 导出 / 恢复(命令行点命令)

# 在线备份(不锁库,推荐给正在运行的库):
sqlite3 workbench.db ".backup 'backups/workbench-20261014.db'"

# 导出为 SQL 文本(适合做版本化迁移/小库):
sqlite3 workbench.db .dump > dump.sql

# 从 SQL 文本恢复:
sqlite3 restored.db < dump.sql

不要在运行中的服务上直接 cp 主库文件——WAL 模式下主库与 -wal 是分离的,只 cp 主库会丢最近的数据。要么走 §8 的 VACUUM INTO / .backup,要么先正常停服务再 cp 三件套(.db + .db-wal + .db-shm)。

05

Go 集成①:modernc 纯驱动(database/sql)

这是本模块的核心。先讲为什么选 modernc,再给完整可运行代码。

5.1 驱动选型结论

维度modernc.org/sqlite v1.60.1mattn/go-sqlite3 v1.14.52
CGO纯 Go,无 CGOCGO,需要 gcc
交叉编译GOOS=linux GOARCH=amd64 一把过Windows 本机交叉编译到 Linux 需要 Linux 工具链(或 zig cc),折腾
1GB 服务器免 gcc,拷贝二进制即跑需在服务器装 build-essential,占磁盘
性能上限够用(工作台量级无感知)略高(贴近原生 C)
本教程结论一律选它(工作台 GORM 驱动 glebarez 也是包它)仅当你本机常驻 Linux、且要榨极限性能时再考虑

5.2 完整示例:建表 / CRUD / 事务 / WAL PRAGMA / 连接池

go.mod(依赖清单,锁版本照抄):

module sqlite-demo

go 1.27

require (
  modernc.org/sqlite v1.60.1
)

main.go(整文件可运行):

package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	_ "modernc.org/sqlite" // 注册 driver name "sqlite"
)

func main() {
	// DSN:打开文件;?_pragma=... 会在每个新连接上自动执行 PRAGMA
	dsn := "workbench.db?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=foreign_keys(ON)&_pragma=synchronous(NORMAL)"

	db, err := sql.Open("sqlite", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// SQLite 下单写者语义下,连接池不要放大。
	// MaxOpenConns=1 写最稳;读多可放到 4-8,但写仍排队。
	db.SetMaxOpenConns(4)
	db.SetMaxIdleConns(2)
	db.SetConnMaxLifetime(time.Hour)

	// 建表
	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS tasks (
		id         INTEGER PRIMARY KEY AUTOINCREMENT,
		title      TEXT    NOT NULL,
		done       INTEGER NOT NULL DEFAULT 0,
		created_at TEXT    NOT NULL
	)`)
	if err != nil {
		log.Fatal(err)
	}

	// 插入
	res, err := db.Exec(
		`INSERT INTO tasks(title, done, created_at) VALUES(?, ?, ?)`,
		"写周报", 0, time.Now().Format(time.RFC3339),
	)
	if err != nil {
		log.Fatal(err)
	}
	id, _ := res.LastInsertId()
	fmt.Println("inserted id =", id)

	// 查询
	var (
		title string
		done  int
	)
	row := db.QueryRow(`SELECT title, done FROM tasks WHERE id = ?`, id)
	if err := row.Scan(&title, &done); err != nil {
		log.Fatal(err)
	}
	fmt.Println("row:", title, done)

	// 事务:BEGIN IMMEDIATE 显式拿写锁,避免 deferred 升级时的死锁
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	_, err = tx.Exec(`UPDATE tasks SET done = 1 WHERE id = ?`, id)
	if err != nil {
		tx.Rollback()
		log.Fatal(err)
	}
	if err := tx.Commit(); err != nil {
		log.Fatal(err)
	}
	fmt.Println("tx committed")
}

运行与交叉编译:

# Windows 本机:
go mod tidy
go run .

# 交叉编译到 1GB Linux 服务器(纯 Go 驱动,一把过,不需要 gcc):
set GOOS=linux
set GOARCH=amd64
go build -o sqlite-demo-linux .
# 然后把 sqlite-demo-linux 拷到服务器,chmod +x 直接跑
连接池注意点(SQLite 专属):① sql.Open 本身不建立连接,第一个 Query 才连;② DSN 里的 _pragma=... modernc 会在每个新连接上自动执行,这正好解决 3.4 说的"连接级 PRAGMA 每个连接都要设"的问题;③ SetMaxOpenConns 别贪大——SQLite 写是全局串行的,连接开多了反而在锁上排队;④ 写密集场景把 MaxOpenConns 设成 1,读多场景 4–8。
06

Go 集成②:glebarez + GORM(工作台默认配置)

工作台(模块 11)的 internal/db/db.go 就是这段代码的展开。这里给出"深度配置版":WAL + busy_timeout + 外键 + 自动迁移 + 事务。

6.1 go.mod 依赖

require (
  github.com/glebarez/sqlite v1.11.0   // 纯 Go GORM 驱动,内部即 modernc v1.60.1
  gorm.io/gorm v1.31.2                 // GORM v2 API 线
)

6.2 db.go:工作台 SQLite 生产配置

package db

import (
	"fmt"
	"time"

	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"

	"workbench/internal/model" // User / Task(见工作台契约 §5)
)

// Open 按 DB_DRIVER 打开数据库;sqlite 分支即工作台默认。
// dbPath 来自环境变量 DB_PATH,例如 ./data/workbench.db
func Open(driver, dbPath string) (*gorm.DB, error) {
	switch driver {
	case "sqlite", "":
		return openSQLite(dbPath)
	case "mysql":
		// 见 16 MySQL 模块:gorm.io/driver/mysql,同一结构
		return nil, fmt.Errorf("mysql 分支见 16 模块")
	default:
		return nil, fmt.Errorf("unknown driver: %s", driver)
	}
}

func openSQLite(dbPath string) (*gorm.DB, error) {
	// DSN:用 _pragma 把连接级 PRAGMA 注入每个新连接。
	dsn := fmt.Sprintf(
		"%s?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=foreign_keys(ON)&_pragma=synchronous(NORMAL)",
		dbPath,
	)

	gdb, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Warn), // 生产用 Warn,别开 Info 刷屏
	})
	if err != nil {
		return nil, err
	}

	// 拿到底层 *sql.DB 设连接池(SQLite 单写者,池要小)
	sqlDB, err := gdb.DB()
	if err != nil {
		return nil, err
	}
	sqlDB.SetMaxOpenConns(4)
	sqlDB.SetMaxIdleConns(2)
	sqlDB.SetConnMaxLifetime(time.Hour)

	// 自动迁移(工作台契约 §5 的 User / Task)
	if err := gdb.AutoMigrate(&model.User{}, &model.Task{}); err != nil {
		return nil, err
	}
	return gdb, nil
}

// WithTx 演示工作台事务写法:短事务、无 IO
func WithTx(gdb *gorm.DB, fn func(tx *gorm.DB) error) error {
	return gdb.Transaction(fn)
}
与工作台契约的对应:模型(User/Task)、端点、统一响应一律遵守工作台契约,这里只是把 internal/db/db.go 的 SQLite 分支配到生产形态。DB_DRIVER=sqlite(或留空)走 SQLite;DB_DRIVER=mysql 切到 16 模块的 MySQL 分支——业务代码一行不改,这就是当初把驱动做成可切换开关的原因。
07

1GB 服务器上的选型决策表

1GB 内存的机器,数据库选型第一原则是"常驻内存越小越好"。按下表决策,不要拍脑袋。

你的场景选谁理由
工作台 / 个人后台 / CLI 工具,写 QPS < 几十SQLite零常驻内存,单文件备份,交叉编译免 gcc
内部报表 / 内容站,读多写极少SQLiteWAL 读并发够用;读多还可以加 18 模块的 Redis 缓存
原型 / MVP 验证期SQLite零前置,先把业务跑通再说
客户网站,多用户同时写、需账号权限MySQL(16 模块)SQLite 单写者扛不住并发写;1GB 机器 MySQL 要调小 buffer pool
复杂查询 / JSONB / 合规审计PostgreSQL(17 模块)SQLite 没有 PG 的类型与约束体系
缓存 / 限流计数 / 队列Redis(18 模块)那是内存加速层,不是 SQLite 的竞争者

1GB 服务器的物理账:MySQL 8 默认配置光缓冲池就想吃 400MB+,PG 类似;而 SQLite 没有常驻进程,你的 Go 二进制吃多少内存它就吃多少。在 1GB 机器上,这个差距就是"能跑"和"OOM"的差距。

08

常见场景与最佳实践:备份 / 恢复 / 并发 / 索引

8.1 热备份:VACUUM INTO(本教程首选)

服务运行中、WAL 未合并时,VACUUM INTO 会生成一个干净、一致、 checkpoint 过的新库文件,全程不锁你的业务库:

-- 在任意连接上执行,目标文件不能已存在
VACUUM INTO '/var/backups/workbench-2026-10-14.db';

-- Go 里就是一行 Exec:
db.Exec(`VACUUM INTO ?`, "/var/backups/workbench-"+time.Now().Format("20060102")+".db")

8.2 定时备份 cron 脚本(服务器上照抄)

#!/usr/bin/env bash
# /usr/local/bin/sqlite-backup.sh —— 工作台 SQLite 每日热备份
set -euo pipefail

DB=/opt/workbench/data/workbench.db
BAK_DIR=/var/backups/workbench
KEEP_DAYS=14

mkdir -p "$BAK_DIR"
STAMP=$(date +%Y%m%d-%H%M%S)
OUT="$BAK_DIR/workbench-$STAMP.db"

# 方式一:用 VACUUM INTO(需要 sqlite3 命令行;库在运行也安全)
sqlite3 "$DB" "VACUUM INTO '$OUT';"

# 备份完顺手校验完整性
sqlite3 "$OUT" "PRAGMA integrity_check;" | grep -q '^ok$'

# 清理超期备份
find "$BAK_DIR" -name 'workbench-*.db' -mtime "+$KEEP_DAYS" -delete

echo "backup ok: $OUT"
# crontab -e 加一行:每天凌晨 3:15 跑
15 3 * * * /usr/local/bin/sqlite-backup.sh >> /var/log/sqlite-backup.log 2>&1

8.3 恢复与只读模式

8.4 并发读与大数据量注意事项

09

常见报错对照表(12 条)

卡住了先查这张表。报错原文照抄进表格第一列。

报错原文原因解决
database is locked / SQLITE_BUSY另一个写事务未提交,或连接池里连接没释放DSN 加 busy_timeout(5000);检查事务是否 Commit/Rollback;写密集把 MaxOpenConns 调小到 1
no such table: tasks库文件路径不对,或 AutoMigrate 没跑确认 DB_PATH 指向的文件;启动时先跑 AutoMigrate;命令行 .tables 核对
table tasks already exists手动建表与 AutoMigrate 冲突,或重复执行 DDLDDL 一律写 CREATE TABLE IF NOT EXISTS;以 GORM AutoMigrate 为准,不要手工建表
SQLITE_BUSY: database is locked(带超时)busy_timeout 没生效,或 WAL 没 checkpoint确认每个连接都设了 PRAGMA busy_timeout=5000;跑 PRAGMA wal_checkpoint;
CGO 交叉编译失败(mattn 场景):gcc: no such file or directory用了 mattn CGO 驱动,Windows 本机没 Linux gcc换 modernc/glebarez 纯驱动(本教程默认);或装 zig cc 工具链——不值得
sql: unknown driver "sqlite3" ...没 import 驱动包的 side-effect,或 driver name 写错modernc 用 import _ "modernc.org/sqlite",driver name 是 "sqlite"(不是 "sqlite3");mattn 才是 "sqlite3"
disk I/O error磁盘满、目录不可写、或 WAL 文件被别的进程删了查磁盘空间 df -h;确认进程对 .db 所在目录有写权限;不要手删运行中的 -wal/-shm
database disk image is malformed库文件损坏(断电、磁盘故障、只拷了主库没拷 WAL)PRAGMA integrity_check;;从最近备份恢复;平时用 VACUUM INTO/.backup 而不是裸 cp
unable to open database file目录不存在 / 路径拼错 / 权限不足DB_PATH 的父目录要先 mkdir(如 ./data/);检查 systemd 服务的 WorkingDirectory 与用户权限
锁表导致写超时:请求挂住后报 context deadline exceeded长事务里夹了网络请求/外部调用,占着写锁不放事务体里只做 DB 操作;外部调用移出事务;写事务必须短
外键没生效:删了父行子行还在SQLite 默认 foreign_keys=OFF,没开DSN 加 _pragma=foreign_keys(ON),且确认每个新连接都执行到
WAL 文件巨大不回收(workbench.db-wal 几个 G)长读事务一直不结束,checkpoint 无法推进关掉泄漏的长读连接;手动 PRAGMA wal_checkpoint(TRUNCATE);
10

本模块验收

做完以下两项,本模块与 M3 清单里的"SQLite(WAL + 备份)集成达标"同时达成。

√验收项怎么算过
☐工作台 SQLite 深度配置跑通:用 §6 的 db.go 配置(WAL + busy_timeout=5000 + foreign_keys=ON + synchronous=NORMAL + 小连接池)启动工作台启动后目录出现 workbench.db / -wal / -shm;登录、任务 CRUD 正常;PRAGMA foreign_keys; 返回 1
☐一次 VACUUM INTO 热备份演练:服务运行中执行 VACUUM INTO,再对备份跑 integrity_check备份文件生成;PRAGMA integrity_check; 返回 ok;原服务无中断
☐交叉编译验证:本机 GOOS=linux GOARCH=amd64 go build 一把过(无 gcc 报错),二进制拷到服务器能跑服务器上 ./workbench 启动成功,/healthz 返回 ok

过不了怎么办:先查 §9 报错表;再不行把"报错原文 + 复现步骤 + 相关 PRAGMA"按 08 §6.3 的调试纪律打包给 AI。本模块不要求你去翻官网——该讲的都在上面了。

11

来源表

SQLite 版本 3.53.4(2026-07-24)与官方变更记录https://sqlite.org/changes.html
modernc.org/sqlite v1.60.1(纯 Go 驱动)https://pkg.go.dev/modernc.org/sqlite
glebarez/sqlite v1.11.0(GORM 纯 Go 驱动)https://pkg.go.dev/github.com/glebarez/sqlite
mattn/go-sqlite3 v1.14.52(CGO 备选)https://github.com/mattn/go-sqlite3/releases
GORM v1.31.2(v2 API 线)https://pkg.go.dev/gorm.io/gorm
PRAGMA journal_mode=WAL / busy_timeout / foreign_keys / synchronous 语义;VACUUM INTO 热备份;单写者语义https://sqlite.org/pragma.html · https://sqlite.org/wal.html · https://sqlite.org/lang_vacuum.html
四数据库分工、工作台默认 DB_DRIVER=sqlite、版本纪律七规则:本系列 08 §8.1 / 09 §4 / 工作台契约file:///D:/02-Docs/金融知识/08-闭关总纲.html · file:///D:/02-Docs/金融知识/09-环境搭建与版本清单.html

(编者整理:选型决策表、连接池参数、cron 备份脚本、报错对照表为基于官方文档与工作台契约的工程化整理,无外部独立来源。)