00 / 00

数据库

了解 01MVP 的 D1、SQLite、Drizzle schema、migration 和多运行时适配方式。

01MVP 使用一套 Drizzle SQLite schema。生产数据库是 Cloudflare D1,本地开发和未来国内自托管都保持 SQLite 语义。

运行方式

运行位置数据库访问方式
Cloudflare WorkersDB D1 binding,Worker 内直接访问
Zeabur / Docker / NodeD1_PROXY_TOKEN 保护的 D1 binding 代理
本地开发和 E2EWrangler 管理的本地 SQLite 数据
国内自托管普通 SQLite 适配器、持久卷和备份

业务代码统一调用 getDb(),不直接依赖某个部署平台。

为什么没有使用 PostgreSQL

当前产品的数据量、访问量和写入并发不需要 PostgreSQL 的扩展、复杂事务或高并发写入能力。使用 D1 可以减少独立数据库服务、连接池和备份设施,也能把应用与数据统一放到 Cloudflare。

这不是说 PostgreSQL 不好,而是现阶段没有必要为未发生的需求支付复杂度。出现下面任一条件时,再做迁移评估:

  • 持续的高并发写入已经成为实际瓶颈。
  • 必须使用 PostGIS、全文检索扩展或其他 PostgreSQL 专属能力。
  • 分析型复杂查询超出 D1 的适用范围。
  • 业务正确性必须依赖行级锁、特定隔离级别或 PostgreSQL 专属事务语义。

默认不要让 SQLite 和 PostgreSQL 同时充当主数据库。双写会带来一致性、补偿、迁移和排障成本。确实需要搜索、分析等专用系统时,可以从 SQLite 主库通过事件或异步任务同步派生数据,但不要让两个数据库共同决定同一份业务事实。

Schema 与数据表示

Schema 位于 products/01mvp/packages/db/src/schema/

  • 时间使用 Unix 毫秒整数。
  • 布尔值存为 0/1,由 Drizzle 映射为 boolean
  • JSON 存为文本,由 Drizzle 负责序列化。
  • 金额和积分等需要精确表示的值使用十进制文本,避免浮点误差。

应用 SQL 不使用 ILIKE、PostgreSQL cast、advisory lock 等专属语法。跨语句原子操作优先使用 D1 batch、条件更新和经过审查的 SQLite trigger。

常用命令

修改 schema 后先生成 migration:

vpr @01mvp/product#db:generate

应用到本地 D1:

vpr @01mvp/product#db:migrate

应用到生产 D1:

vpr @01mvp/product#db:deploy

生产 migration 必须先提交并审查,再在部署新代码之前执行。不要在应用启动时自动修改生产 schema。

查询示例

import { eq } from "drizzle-orm";
import { getDb, schema } from "@01mvp/db";

const db = getDb();
const rows = await db
  .select()
  .from(schema.user)
  .where(eq(schema.user.id, userId));

国内部署

D1 本身是 Cloudflare 服务,不能原样搬进国内服务器;可移植的是 SQLite schema、migration 和应用查询。国内部署时实现普通 SQLite 运行时适配器,并明确配置:

  1. 持久磁盘或持久卷。
  2. 定时备份与恢复演练。
  3. 单写节点,或能保证 SQLite 写入安全的部署拓扑。
  4. migration 在新版本上线前显式执行。

只要继续遵守 SQLite 可移植边界,业务层不需要因为部署地点改变而重写。

这篇文档有问题?