
RxDB RxStorage 层详解为每种运行环境选择与组合最佳存储引擎【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdbRxStorage 是 RxDB 的存储抽象层它把「数据库内核」与「底层存储引擎」彻底解耦RxDB 本身并不直接写数据而是把所有文档读写、查询、变更事件都委托给一个实现了 RxStorage 接口的存储实现从而可以在浏览器、Node.js、Electron、React Native、Capacitor 等不同环境下自由切换底层数据层。读完本文你将掌握 RxStorage 的接口模型、官方全部存储实现与包装插件的适用场景并能通过「存储叠加」组合出面向加密、高查询负载、低写入延迟等不同目标的数据库配置。为什么需要 RxStorage 抽象层RxDB 不是一款自包含self-contained的数据库。从源码结构看RxDB 的核心src/rx-database.ts、src/rx-collection.ts 等只依赖一个抽象的存储契约真正的数据存放在某个 RxStorage 接口 实现中。在 src/types/rx-storage.interface.d.ts 中接口头部的注释直接说明了设计意图RxStorage is an interface that abstracts the storage engine. This allows us to use RxDB with different storage engines.这种设计的直接收益是你可以根据 JavaScript 运行环境和性能需求随时换掉底层数据层。例如在 Capacitor 应用中使用 SQLite RxStorage在纯浏览器应用中使用 LocalStorage RxStorage 存数据另外还有面向 Node.js、React Native、NativeScript 等其他运行时的存储。也正因为创建数据库时必须显式指定storageRxDB 才可能在同一个 API 之上横跨浏览器、移动端、桌面端与服务端。在 src/rx-database.ts 中RxDatabase构造器把storage作为公开只读属性保存且数据库名去重键也由storage.name | name组成见 src/rx-database.ts说明存储引擎的身份name是数据库状态的一部分切换存储即切换数据域。RxStorage 接口模型工厂与实例理解 RxStorage 需要区分两个层次存储工厂与存储实例二者都定义在 src/types/rx-storage.interface.d.ts 中。RxStorage存储工厂一个RxStorage是一个「模块化工厂」可以创建多个RxStorageInstance对象其关键成员为成员说明name存储引擎名称用于检测插件不兼容时抛出正确错误rxdbVersion存储所对应的 RxDB 版本用于多版本存储共存时的回退逻辑如 storage migration 插件createStorageInstance(params)创建一个包含某集合 NoSQL 文档的存储实例接口注释还强调存储实例的所有数据输入输出必须是structured-cloneable的——文档数据必须是纯 JSON 对象附件数据使用 Blob不能使用 Map、Set 等无法结构化克隆的结构。这保证了存储数据可以经由 WebWorker、WASM 进程或 BroadcastChannel 传输唯一例外是 WebSocket 传输它会在边界自行序列化。RxStorageInstance存储实例createStorageInstance()返回的实例承载了真正的数据操作每个实例中的文档必须符合同一 schema且 schema 会被自动补全_meta、_rev、_deleted等元数据字段。核心方法如下方法职责bulkWrite(rows, context)批量写入文档每个文档的写入是原子的但整体不构成事务若前一版本不是当前最新修订会返回冲突错误允许部分写入成功、部分失败findDocumentsById(ids, withDeleted)按主键批量取文档withDeleted为 true 时也返回已删除文档出于性能返回数组而非索引对象query(preparedQuery)执行 NoSQL mango 查询并返回结果查询在进入存储前已由查询规划器归一化count(preparedQuery)返回匹配查询的非删除文档数量语义必须与query()结果数组长度一致getAttachmentData(documentId, attachmentId, digest)以 Blob 返回单个附件数据getChangedDocumentsSince?(limit, checkpoint)可选返回指定 checkpoint 之后变更的文档供备份与复制插件增量同步使用未实现时 RxDB 会手动查询并用最后返回的文档做 checkpointchangeStream()返回持续推送所有变更的 Observable 流若存储支持多实例且持久化同一databaseNamecollectionName的其他实例也必须收到变更见 src/rx-storage-multiinstance.tscleanup(minimumDeletedTime)清理_deleted标记文档的墓碑以释放磁盘空间返回true表示全部清理完false表示因避免长时间阻塞还有剩余close()关闭实例并释放内存remove()删除整个数据库及其全部数据另外还有一个可选的underlyingPersistentStorage引用当存储是「内存 持久化」的组合如 memory-synced 存储时复制与迁移会运行在底层持久化存储实例上而不是内存实例上。快速推荐按运行环境选存储原文档给出了一份面向场景的速查推荐浏览器Browser简单搭建、追求小体积用 LocalStorage RxStorage数据集更大时用免费的 Dexie.js storage或者更快、构建体积更小的 IndexedDB RxStorage需要 premium 访问权限。Electron 与 React Native有 premium 访问权限时用 SQLite RxStorage试玩阶段可用 trial-SQLite RxStorage在 Expo 与 React Native 中追求极致性能则用 Expo Filesystem RxStorage。Capacitor有 premium 访问权限用 SQLite RxStorage否则用 LocalStorage storage。从源码看存储工厂的实现形态所有官方存储都遵循同样的工厂模式。以开箱即用的内存存储为例src/plugins/storage-memory/index.ts 中getRxStorageMemory(settings)返回一个name: memory、rxdbVersion: RXDB_VERSION的工厂对象createStorageInstance()会把构造时传入的settings与实例创建参数params.options合并后交给createMemoryStorageInstance()。值得注意的是该模块顶部维护了一个跨实例共享的COLLECTION_STATESMapsrc/plugins/storage-memory/index.ts注释说明即使存储实例被关闭也保留状态方便用它模拟文件系统式与多实例行为——这解释了为什么 Memory 存储「在全部环境中都能用」且适合测试。LocalStorage 存储同样如此src/plugins/storage-localstorage/index.ts 的getRxStorageLocalstorage(settings)返回一个name为RX_STORAGE_NAME_LOCALSTORAGE的RxStorageLocalstorage实例。如果你刚接触 RxDB建议从 LocalStorage RxStorage 开始——它最容易上手、构建体积小。配置示例用「存储叠加」实现复杂需求RxStorage 层非常灵活关键在于包装存储wrapper storage每个包装插件都接收一个{ storage: ... }参数并返回一个新的存储把上游存储包进自己的逻辑里。你可以在createRxDatabase({ storage })处一层层嵌套组合出满足特定目标的存储配置。示例一在浏览器中安全地存储大量数据假设你要构建一个需要在浏览器里尽可能安全地存储大量数据的应用可以组合加密、IndexedDB、压缩与 schema 校验四层既提升安全性又压缩存储体积import { wrappedValidateAjvStorage } from rxdb/plugins/validate-ajv; import { wrappedKeyCompressionStorage } from rxdb/plugins/key-compression; import { wrappedKeyEncryptionCryptoJsStorage } from rxdb/plugins/encryption-crypto-js; import { getRxStorageIndexedDB } from rxdb-premium/plugins/storage-indexeddb; const myDatabase await createRxDatabase({ storage: wrappedValidateAjvStorage({ storage: wrappedKeyCompressionStorage({ storage: wrappedKeyEncryptionCryptoJsStorage({ storage: getRxStorageIndexedDB() }) }) }) });分层顺序是有讲究的最顶层放 schema 校验确保 schema 错误清晰可读且报错内容不包含加密后的密文或压缩后的乱码加密放在压缩内部因为对压缩后的数据进行加密更高效压缩先行缩小了需要加密的数据量。从源码看这些wrapped*函数都只是对原存储的浅层增强。例如 src/plugins/key-compression/index.ts 的wrappedKeyCompressionStorage({ storage })用Object.assign({}, args.storage, { createStorageInstance: ... })生成新存储只重写createStorageInstance()其余接口全部透传src/plugins/encryption-crypto-js/index.ts 的wrappedKeyEncryptionCryptoJsStorage同样如此。这意味着包装存储与被包装存储对外是「同一个 RxStorage 接口」可以无限层叠也解释了为何组合顺序能精确控制数据在各层的处理路径。加密与键压缩的完整原理分别见 encryption 与 key-compression。示例二高查询负载如果要针对「复杂查询要跑得飞快」来优化可以用sharding分片叠加worker工作线程查询可以并行地跑在多个线程里而不是单个 JavaScript 进程。由于 worker 初始化可能拖慢首屏加载再套一层 localstorage-meta-optimizer 来改善初始化时间import { getRxStorageSharding } from rxdb-premium/plugins/storage-sharding; import { getRxStorageWorker } from rxdb-premium/plugins/storage-worker; import { getRxStorageIndexedDB } from rxdb-premium/plugins/storage-indexeddb; import { getLocalstorageMetaOptimizerRxStorage } from rxdb-premium/plugins/storage-localstorage-meta-optimizer; const myDatabase await createRxDatabase({ storage: getLocalstorageMetaOptimizerRxStorage({ storage: getRxStorageSharding({ storage: getRxStorageWorker({ workerInput: path/to/worker.js, storage: getRxStorageIndexedDB() }) }) }) });这里workerInput指向 worker 脚本路径存储本体在 worker 内运行 IndexedDB分片存储把文档切分到多个数据库实例上以如 IndexedDB 这类存储上换取向上的性能提升最外层的 meta optimizer 则把 RxDB 建库、建集合所需的纯键值元数据放进 localStorage缩短首屏初始化。示例三写入与简单读取的低延迟如果应用以简单读写为主、追求低延迟可以用memory-mapped 存储把数据拉进内存做读写用OPFS 存储做主线程持久化——初始化时从磁盘把大块数据载入内存的延迟更低。这里刻意不使用 worker因为主线程与 worker 之间的数据传输会引入额外延迟import { getLocalstorageMetaOptimizerRxStorage } from rxdb-premium/plugins/storage-localstorage-meta-optimizer; import { getMemoryMappedRxStorage } from rxdb-premium/plugins/storage-memory-mapped; import { getRxStorageOPFSMainThread } from rxdb-premium/plugins/storage-worker; const myDatabase await createRxDatabase({ storage: getLocalstorageMetaOptimizerRxStorage({ storage: getMemoryMappedRxStorage({ storage: getRxStorageOPFSMainThread() }) }) });三个示例共同展示了 RxStorage 架构的核心理念底层引擎决定「数据落在哪里、如何持久化」包装插件决定「数据如何被变换、在哪里执行」二者正交组合即可为几乎任何约束安全、吞吐、延迟、体积定制存储栈。全部 RxStorage 实现一览核心实现存储说明Memory数据以纯对象保存在 JavaScript 进程内存中速度极快可在所有环境使用。Read moreLocalStorage基于浏览器 localStorage API 的存储搭建最简单、构建体积小适合 RxDB 新手入门。Read more IndexedDB基于原生 IndexedDB对大多数用例而言与 OPFS 存储并列为浏览器中性能最好的选择。Read more OPFS基于 File System Access APIOPFS在浏览器中使用 RxDB 时是除内存存储外性能最好的非内存存储。Read more Filesystem Node最适合在 Node.js 进程或 Electron 中使用 RxDB 的场景。Read more存储包装插件Storage Wrapper Plugins插件说明 Worker包装任意 RxStorage把存储跑在浏览器 WebWorker 或 Node.js Worker Thread 中把 CPU 负载从主进程移出改善应用可感知性能。Read more SharedWorker包装任意 RxStorage把存储跑在 SharedWorker仅浏览器中同样实现主进程减负。Read moreRemote面向「远程存储 异步消息通道」的通信而设计远程端可以是另一个 JavaScript 进程甚至另一台主机多被 Worker、Electron-ipc 等存储内部使用。Read more Sharding在部分 RxStorage如 IndexedDB上把文档分片到多个数据库实例可带来巨大的性能提升可包装任意存储为分片存储。Read more Memory Mapped包装任意存储创建一个用于查询与写入的内存存储同时把数据落到底层存储做持久化主要价值是提升查询/写入性能而数据仍在磁盘。Read more Localstorage Meta Optimizer包装任意存储集合文档仍走原存储但把 RxDB 建库建集合所需的纯键值元数据放进 localStorage以优化首屏加载时间仅限浏览器。Read moreElectron IpcRenderer IpcMain在 Electron 中推荐把 RxStorage 跑在主进程、RxDatabase 跑在渲染进程通过 rxdb electron 插件创建远程 RxStorage 供渲染进程消费。Read more第三方引擎类存储存储说明 Expo Filesystem通过 JSI 绑定绕过 RN bridge把 OPFS 级的高速能力带给 React Native / Expo是 React Native 上最快的存储引擎。Read more SQLite在Node.js、Electron、React Native、Cordova、Capacitor上都有出色的性能表现。Read moreDexie.js基于 Dexie.js 这个 IndexedDB 封装库实现。Read moreMongoDB服务端使用 RxDB 的选择之一基于流行的 MongoDB NoSQL 数据库安全、可扩展、高性能。Read moreDenoKV在 Deno 中使用 RxDB 的方案基于 Deno 的 Key Value Store安全、可扩展、高性能。Read moreFoundationDB服务端使用 RxDB 的另一个选择基于 FoundationDB安全、容错、高性能。Read more如何挑选与验证你的存储组合选型时可以按以下路径推进确定运行环境浏览器优先看 IndexedDB / OPFS / Dexie.js / LocalStorageNode.js 看 Filesystem Node / SQLite / MongoDB / FoundationDB移动端看 SQLite / Expo Filesystem / LocalStorageDeno 看 DenoKV。明确性能瓶颈查询吞吐优先考虑 Worker Sharding简单读写低延迟优先考虑 Memory Mapped OPFS初始化速度优先考虑 Localstorage Meta Optimizer。确定安全需求需要加密与压缩时按「压缩在加密之前、校验在最外层」的顺序叠加包装层。确认许可与访问级别部分存储如 IndexedDB、OPFS、SQLite、Sharding、Worker 等标注 需要 premium 访问权限LocalStorage、Memory、Dexie.js、Remote 等为免费可用。用测试印证行为仓库的 test/unit/rx-storage-implementations.test.ts 会以统一的用例矩阵校验各存储实现test/unit/rx-storage-query-correctness.test.ts 验证查询语义一致性test/unit/rx-storage-helper.test.ts 覆盖辅助逻辑——自研或选型存储时可参考这些测试对齐行为契约。总结RxStorage 是 RxDB 赖以横跨全部 JavaScript 运行时的架构基石一个定义在 src/types/rx-storage.interface.d.ts 的接口加上一组「工厂—实例」实现与可无限叠加的包装插件让你不必改变任何业务代码就能更换、组合、优化底层数据层。无论是浏览器中的 LocalStorage 快速起步、IndexedDB/OPFS 的高性能持久化还是 Electron/React Native 中的 SQLite、服务端的 MongoDB/FoundationDB乃至通过 Worker、Sharding、Memory Mapped、Meta Optimizer 等包装插件实现的线程级并行与低延迟读写你都可以基于本文的组合模式在createRxDatabase({ storage })一处完成定制。【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考