SQLite local file quickstart 的核心責任是建立後續 backup、WAL、migration 與 fixture lab 共用的 database file。這個 lab 把 SQLite 從抽象服務選型轉成可觀察的檔案、schema、PRAGMA、transaction 與 sidecar artifact。

本文的驗收標準是:你能建立一個可重建的 app.db,知道它的 schema version、journal mode、foreign key 設定、seed data 與 cleanup 路徑。

Lab Directory

Lab directory 的核心責任是把 SQLite artifact 放在隔離資料夾,避免和正式檔案混淆。以下命令建立一個可刪除的本地工作區。

1mkdir -p /tmp/sqlite-lab
2cd /tmp/sqlite-lab
3rm -f app.db app.db-wal app.db-shm

驗收 artifact 是 /tmp/sqlite-lab/app.db。後續 lab 可以沿用這個路徑,也可以每次從頭建立。

Baseline Schema

Baseline schema 的核心責任是建立一組能測 transaction、constraint、index 與 query 的小型資料模型。這裡使用 accountsledger_entries,因為它們能清楚展示 foreign key 與金額 invariant。

 1sqlite3 app.db <<'SQL'
 2PRAGMA journal_mode = WAL;
 3PRAGMA foreign_keys = ON;
 4PRAGMA user_version = 1;
 5
 6CREATE TABLE accounts (
 7  id INTEGER PRIMARY KEY,
 8  owner_name TEXT NOT NULL,
 9  status TEXT NOT NULL CHECK (status IN ('active', 'closed')),
10  created_at TEXT NOT NULL
11) STRICT;
12
13CREATE TABLE ledger_entries (
14  id INTEGER PRIMARY KEY,
15  account_id INTEGER NOT NULL REFERENCES accounts(id),
16  amount_cents INTEGER NOT NULL CHECK (amount_cents != 0),
17  idempotency_key TEXT NOT NULL UNIQUE,
18  created_at TEXT NOT NULL
19) STRICT;
20
21CREATE INDEX idx_ledger_entries_account_created
22ON ledger_entries(account_id, created_at);
23SQL

這段 schema 的重點是明確資料合約。STRICTCHECKFOREIGN KEYUNIQUE 讓 fixture 更接近正式資料責任,也讓後續 migration lab 有可驗證的 invariant。

Seed Data

Seed data 的核心責任是建立可重跑的測試資料。每筆 ledger entry 都有 idempotency key,讓後續 edge / retry 設計可以沿用。

 1sqlite3 app.db <<'SQL'
 2PRAGMA foreign_keys = ON;
 3
 4BEGIN;
 5INSERT INTO accounts(id, owner_name, status, created_at)
 6VALUES
 7  (1, 'Ada', 'active', '2026-05-21T00:00:00Z'),
 8  (2, 'Lin', 'active', '2026-05-21T00:05:00Z');
 9
10INSERT INTO ledger_entries(account_id, amount_cents, idempotency_key, created_at)
11VALUES
12  (1, 1200, 'seed-ada-credit-1', '2026-05-21T00:10:00Z'),
13  (1, -200, 'seed-ada-debit-1', '2026-05-21T00:12:00Z'),
14  (2, 900, 'seed-lin-credit-1', '2026-05-21T00:15:00Z');
15COMMIT;
16SQL

Seed 完成後先跑基本查詢。這一步確認 schema、constraint 與 index 入口都可用。

1sqlite3 app.db <<'SQL'
2.headers on
3.mode column
4SELECT a.id, a.owner_name, SUM(l.amount_cents) AS balance_cents
5FROM accounts a
6JOIN ledger_entries l ON l.account_id = a.id
7GROUP BY a.id, a.owner_name
8ORDER BY a.id;
9SQL

預期輸出應顯示 Ada 餘額 1000,Lin 餘額 900

PRAGMA Snapshot

PRAGMA snapshot 的核心責任是把連線設定變成 evidence。SQLite 的部分設定與 connection 有關,因此 lab 要明確查出當前狀態。

1sqlite3 app.db <<'SQL'
2.headers on
3.mode column
4PRAGMA journal_mode;
5PRAGMA foreign_keys;
6PRAGMA user_version;
7PRAGMA integrity_check;
8SQL

驗收重點如下:

欄位期望結果意義
journal_modewal後續可觀察 -wal sidecar
foreign_keys1constraint 在連線上已啟用
user_version1migration 起點清楚
integrityokdatabase file 基本健康

Transaction Sample

Transaction sample 的核心責任是建立後續 busy / migration lab 的共同語言。SQLite transaction 成功時要同時更新資料與保護 invariant。

1sqlite3 app.db <<'SQL'
2PRAGMA foreign_keys = ON;
3BEGIN IMMEDIATE;
4INSERT INTO ledger_entries(account_id, amount_cents, idempotency_key, created_at)
5VALUES (1, 300, 'manual-ada-credit-1', '2026-05-21T00:20:00Z');
6COMMIT;
7SQL

BEGIN IMMEDIATE 會提早取得 write lock。這讓後續 WAL busy reproduction 可以直接展示 single writer boundary。

File Artifact Check

File artifact check 的核心責任是讓讀者看到 SQLite 由 .db 與可能存在的 sidecar 共同構成。WAL mode 可能建立 -wal-shm sidecar,backup / copy / restore runbook 要理解這些檔案。

1ls -lh app.db app.db-wal app.db-shm

若 sidecar 暫時未出現,可以再寫入一筆資料或保持連線開啟。Sidecar 是否存在取決於 WAL 狀態、checkpoint 與 connection lifecycle。

Cleanup

Cleanup 的核心責任是讓 lab 可以重跑。若要重新開始,刪除 database 與 sidecar。

1rm -f /tmp/sqlite-lab/app.db /tmp/sqlite-lab/app.db-wal /tmp/sqlite-lab/app.db-shm

完成本篇後,下一步可以進入 backup restore drillWAL busy reproduction