第4章 本地数据引擎选型:SQLite、IndexedDB、Dexie、WatermelonDB 的架构权衡与选型决策
4.1 架构边界与上下文
本地数据引擎位于离线优先架构的持久化存储层,上接数据访问层(Repository/DAO),下接文件系统或浏览器内置存储。它在离线期间承载所有结构化数据的写入、查询、索引、事务管理,并在恢复在线后充当同步引擎的数据基座。本章比较的四款引擎涵盖了移动原生(SQLite)、浏览器原生(IndexedDB)以及基于其上封装的现代化库(Dexie.js、WatermelonDB)。
选型边界明确为:浏览器端离线应用(PWA) 与 移动端混合/原生应用 两种场景。不考虑后端持久化。
架构提示: 选型初期即应将引擎视为“可替换组件”,通过依赖倒置原则抽象出统一存储接口,降低后续迁移成本。
4.2 系统分层与模块职责
在典型离线优先架构中,本地数据引擎参与以下分层:
- 网络同步层: 管理远程 API 推拉,将增量变更写入本地引擎。
- 数据访问层(Repository/DAO): 封装 CRUD 逻辑,对外提供事务性接口,内部调用引擎 API。
- 本地数据引擎: 负责物理存储、索引、查询优化、事务与并发控制。
- 持久化介质: 文件系统(SQLite)、浏览器 IndexedDB 存储。
4.3 选型权衡:对比矩阵
| 维度 | SQLite | IndexedDB | Dexie.js | WatermelonDB |
|---|---|---|---|---|
| 运行环境 | 原生(Android/iOS/桌面) | 浏览器(所有现代浏览器) | 浏览器(封装 IndexedDB) | 原生 + 浏览器(React Native / Web) |
| 事务支持 | 完整 ACID | 有限(单连接序列) | 支持(自动事务管理) | 内置事务 + 同步标记 |
| 查询能力 | SQL(JOIN、子查询) | 游标 + 索引 | 链式查询(类似 LINQ) | 懒加载 + 关联查询 |
| 索引与排序 | 多字段复合索引 | 多字段索引(需手动) | 自动索引声明 | 自动索引 + observable |
| 离线同步集成 | 需自建同步逻辑 | 需自建 | 可通过插件扩展 | 内置同步协议(pull/push) |
| 包体积与加载 | ~500KB(sqlite3.c) | 浏览器原生,无额外体积 | ~45KB(gzip) | ~100KB(gzip,含 lodash) |
| 性能(10万行) | 批量插入 ~50ms | 批量插入 ~200ms | 优化后 ~120ms | 惰性写入 + 延迟渲染,首屏快 |
注意: IndexedDB 在 iOS 上的私有模式(Safari 无痕浏览)会耗尽存储空间,且清除数据时难以保留;此场景下应回退至内存存储或提前检测异常。
4.4 数据流与信任链路
本地数据引擎不仅负责持久化,还承担离线信任锚点的角色。每次从网络同步的数据须经过:
- 验证阶段: 检查记录 schema 版本、冲突向量(如 Lamport 时间戳)
- 写入阶段: 使用引擎事务保证原子写入
- 索引刷新: 确保查询可立即命中
- 通知层: 触发 UI 更新(如 WatermelonDB 的 observable)
信任链路要求引擎不得丢失已提交事务,且能检测存储介质异常(如 SQLite 的 fsync 失败、IndexedDB 的 quota 超限)。
4.5 风险点与避坑指南
- SQLite 的多写并发: 在移动端 WAL 模式下可支持读写并发,但写写仍排他;需使用连接池或序列化写入。
- IndexedDB 的异步陷阱: 所有操作异步,不当的 Promise 链容易导致事务提前关闭。
- Dexie.js 的版本迁移: Schema 变更时需显式升级版本号,否则数据丢失。
- WatermelonDB 的惰性加载: 大量关联查询可能触发 N+1 问题,需使用 prefetch 或批量加载。
- 跨平台一致性: 如果同时使用 Web + Native 混合,选型应优先考虑 cortex(如 WatermelonDB)封装统一的存储接口。
4.6 落地步骤
- 根据运行环境锁定候选引擎(浏览器 → IndexedDB/Dexie/WatermelonDB;原生 → SQLite/WatermelonDB)
- 制作 POC,对核心场景(离线写入 1000 条 + 复合查询 + 同步冲突)进行压测
- 评估学习曲线与调试工具链(如 SQLite 可使用 DB Browser,IndexedDB 可使用 Chrome DevTools)
- 设计存储抽象层,将引擎依赖收口到单一 Repository 实现
- 实现启动时的 schema 迁移脚本与降级路径
- 编写集成测试覆盖:异常写入、同步恢复、存储空间不足
4.7 验收标准
| 验收项 | 通过标准 |
|---|---|
| 离线写入正确性 | 模拟离线写入 5000 条数据,恢复在线后无丢失、无重复 |
| 查询响应时间 | 10 万行数据下,复合条件查询 ≤ 200ms |
| 事务隔离性 | 并发写事务不产生脏读取或部分更新 |
| 存储限制处理 | 达到配额前触发预先警告,且写操作优雅失败 |
| 版本迁移 | 从 v1 迁移到 v3 schema,历史数据完整保留 |
选型决策摘要:
- 纯浏览器端、快速迭代: Dexie.js(兼顾易用性与性能)
- 移动原生重度离线、复杂查询: SQLite(配合 Room 或 DataStore)
- 跨平台(React Native + Web)、同步集成: WatermelonDB(内置 observable + 同步协议)
- 轻量 POC、无需额外库: IndexedDB(但小心 iOS 私有模式)