摘要
WatermelonDB 用于快速处理 React Native 应用程序中的大量本地数据。 是一个 离线优先的响应式数据库框架。内部存储主要使用 SQLite,但开发人员不再直接编写 SQL,而是通过 Schema、Model、Query、Writer 和 Sync API 构建应用程序数据流。对于简单的缓存或存储一些设置来说,这可能有点大材小用,但对于需要数千到数万条记录、同步、关系数据和自动屏幕更新的应用程序来说,它比直接使用 SQLite 更有效率。
如果你想先整理一下 SQLite 概念, Serverless 基于文件的 DB 的优点、局限性、WAL 和锁定错误解决方案是 SQLite 实用指南 ↗已经单独详细总结了。
验证标准:在撰写本文时,npm 的最新版本是
@nozbe/watermelondb确认为0.28.0,但官方文档页面显示为0.27.1。在安装之前,检查项目的React Native/Expo版本和WatermelonDB版本/问题会更安全。
目录
- 背景
- 什么是西瓜数据库?
- 为什么 WatermelonDB 很快
- React Native 基本用法
- SQLite 和 WatermelonDB 的比较
- 同步结构
- 实际阻塞和解决方向
- 何时使用它,何时避免它?
- 结论
- 参考资料
背景
创建 React Native 应用程序时,起初似乎只需调用服务器 API 并绘制屏幕就足够了。但当下一个请求到来时,情况就发生了变化。
- 即使网络断开也必须可以创建/编辑。
- 该应用程序需要在启动后立即快速显示数千个任务、消息、订单和客户数据。
- 当本地数据发生变化时,相关屏幕应自动更新。
- 服务器和本地数据必须定期同步。
- 需要的是关系数据,而不是简单的键值存储。
此时经常想到的选项是 SQLite。 SQLite接近移动本地DB的事实标准,具有良好的性能和稳定性。然而,在React Native中直接使用SQLite时,SQL编写、结果映射、屏幕更新、同步冲突处理、迁移等都必须直接在应用程序代码中设计。
WatermelonDB 是一个试图解决这个问题的工具。而不是取代 SQLite, 一个框架,在 SQLite 之上构建适合 React/React Native 应用程序的数据层。附近
什么是西瓜数据库?
WatermelonDB 是一个开源的数据库管理工具,它可以帮助您更好地管理数据。官方介绍的要点如下。
- 它旨在快速处理 React Native 和 React 应用程序中的大量本地数据。
- 不是一次性将所有数据加载到 JavaScript 内存中,而是在需要时延迟读取。
- 查询在本机数据库(例如 SQLite)中执行。
- 通过提供基于RxJS的可观察结构,可以在数据变化时自动更新UI。
- 您可以通过连接自己的后端来实现离线优先级同步。
换句话说,WatermelonDB 不仅仅是一个 SQLite 包装器。以下各层一起提供。
| 成分 | 角色 |
|---|---|
| Schema | 表和列定义 |
| Model | 定义您的应用程序处理的数据对象 |
| Collection | 记录特定表的访问单元 |
| Query API | 基于条件的查找 |
| Writer | 编写安全捆绑创建/修改/删除操作的事务概念 |
| Observable | 数据变化时自动反映UI |
| Sync API | 服务器和本地数据库之间的更改同步 |
为什么 WatermelonDB 很快
WatermelonDB 的性能点并不仅仅以“它很快,因为它是 SQLite”结束。更重要的部分是 不会将不必要的数据拉入 JavaScript 区域的结构全部。
一般状态管理+持久化的方式很容易在app启动时加载大量数据到JS内存中。数百条数据时没有问题,但当数量增加到数千或数万时,应用程序启动速度和内存占用会明显变差。
WatermelonDB 通过以下方式减少了这个问题:
1.启动应用程序时,不要将整个DB加载到JS内存中。 2. 仅在必要的屏幕上执行必要的查询。 3.条件搜索是通过DB查询来处理的,而不是JS数组过滤。 4. 只有连接到已更改数据的组件才会更新为可观察的。
如果您在 React Native 应用程序中遇到“随着本地数据量的增加,应用程序变得越来越重”的问题,那么值得考虑 WatermelonDB。
React Native 基本用法
下面的示例是一个用于存储博客文章和评论的简单结构。在实际项目中,您可以调整文件夹结构并相应地导入别名。
1. 安装
npm install @nozbe/watermelondb
npm install -D @babel/plugin-proposal-decorators
或者,如果您使用 Yarn,请按如下方式安装。
yarn add @nozbe/watermelondb
yarn add --dev @babel/plugin-proposal-decorators
WatermelonDB使用装饰器语法,因此需要Babel配置。
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }]
]
}
在 iOS 上,可能需要设置 CocoaPods。官方文档是 simdjson 添加广告连播 pod install引导您完成
# ios/Podfile
pod 'simdjson', path: '../node_modules/@nozbe/simdjson', modular_headers: true
cd ios
pod install
我经常被困在这里。尤其 use_frameworks!、Expo 和 React Native 新架构组合需要根据项目状态进行额外确认。
2. 模式定义
在WatermelonDB中,首先定义了DB Schema。表名和列名通常是 snake_case使用 。
// src/db/schema.js
import { appSchema, tableSchema } from '@nozbe/watermelondb'
export const mySchema = appSchema({
version: 1,
tables: [
tableSchema({
name: 'posts',
columns: [
{ name: 'title', type: 'string' },
{ name: 'body', type: 'string' },
{ name: 'is_pinned', type: 'boolean' },
],
}),
tableSchema({
name: 'comments',
columns: [
{ name: 'body', type: 'string' },
{ name: 'post_id', type: 'string', isIndexed: true },
],
}),
],
})
post_id 这类经常用于关系查询的列,建议加上 isIndexed: true。就像在 SQLite 中索引很重要一样,在 WatermelonDB 中,符合查询模式的索引设计也会影响性能。
3. 模型定义
如果 Schema 是实际的数据库结构,则 Model 是要在应用程序代码中使用的对象。
// src/db/models/Post.js
import { Model } from '@nozbe/watermelondb'
import { field, children, writer } from '@nozbe/watermelondb/decorators'
export default class Post extends Model {
static table = 'posts'
static associations = {
comments: { type: 'has_many', foreignKey: 'post_id' },
}
@field('title') title
@field('body') body
@field('is_pinned') isPinned
@children('comments') comments
@writer async updateTitle(title) {
await this.update(post => {
post.title = title
})
}
}
// src/db/models/Comment.js
import { Model } from '@nozbe/watermelondb'
import { field, relation } from '@nozbe/watermelondb/decorators'
export default class Comment extends Model {
static table = 'comments'
static associations = {
posts: { type: 'belongs_to', key: 'post_id' },
}
@field('body') body
@relation('posts', 'post_id') post
}
这里重要的一点是数据库更改不是在任何地方完成的。在WatermelonDB中,可以创建、修改、删除 database.write() 或者 @writer 从内部处理它。
4. 创建数据库
// src/db/index.js
import { Database } from '@nozbe/watermelondb'
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite'
import { mySchema } from './schema'
import Post from './models/Post'
import Comment from './models/Comment'
const adapter = new SQLiteAdapter({
schema: mySchema,
})
export const database = new Database({
adapter,
modelClasses: [Post, Comment],
})
5. 数据创建与查询
// 글 생성
const newPost = await database.write(async () => {
return await database.get('posts').create(post => {
post.title = 'WatermelonDB 시작하기'
post.body = 'React Native에서 로컬 DB를 다루는 방법'
post.isPinned = false
})
})
// 글 목록 조회
import { Q } from '@nozbe/watermelondb'
const pinnedPosts = await database
.get('posts')
.query(Q.where('is_pinned', true))
.fetch()
6. 与React组件连接
这就是 WatermelonDB 的优势所在。如果将其连接到可观察对象,则屏幕会在数据更改时自动更新,而不仅仅是获取一次数据。
import React from 'react'
import { Text, View } from 'react-native'
import { withObservables } from '@nozbe/watermelondb/react'
function PostItem({ post }) {
return (
<View>
<Text>{post.title}</Text>
<Text>{post.body}</Text>
</View>
)
}
const enhance = withObservables(['post'], ({ post }) => ({
post,
}))
export default enhance(PostItem)
列表还可以作为可观察量连接到查询。由于这种结构,减少了每次手动创建“数据库更改→状态更新→列表重新检查→屏幕更新”流程的需要。
SQLite 和 WatermelonDB 的比较
WatermelonDB 并不是一个完全取代 SQLite 的独立数据库,而是更接近于一个允许 SQLite 在 React Native 应用程序中以更高抽象的方式使用的工具。所以比较的标准不是“SQLite更好/WatermelonDB更好” 您需要什么级别的控制和生产力?全部。
| 物品 | 直接使用SQLite | WatermelonDB |
|---|---|---|
| 基本人格 | 本地关系数据库引擎/API | 基于SQLite的响应式数据库框架 |
| 数据访问 | 编写自己的 SQL | 使用模型、集合、查询 API |
| 表现 | 如果你的查询设计得当的话会非常快 | 延迟加载+原生数据库查询+可观察结构 |
| 反应用户界面更新 | 需要直接的状态管理 | 可通过 observable 自动更新 |
| 关系数据 | 直接使用 SQL 连接/查询 | 提供关联和关系模型 |
| 迁移 | 设计你自己的 | 使用 WatermelonDB 迁移 API |
| 同步 | 自己实施 | 提供同步原语和协议,但直接需要后端 |
| 运行曲线 | 如果您了解 SQL,则可以轻松访问 | 需要学习WatermelonDB规则以及装饰器和写入器模式 |
| 调试 | 基于DB文件/SQL的跟踪 | WatermelonDB 抽象和本机构建问题必须一起看待 |
| 合适的应用程序 | 简单的本地存储和 SQL 控制很重要的应用程序 | 离线优先、高数据、自动 UI 刷新、以同步为中心的应用程序 |
什么时候直接使用SQLite更好
对于以下应用程序,无需引入WatermelonDB。
- 没有太多数据可存储。
- 仅保存简单的设置、缓存和最近的搜索词。
- 自己编写和调优SQL更为重要。
- 不需要自动连接到 React UI 的可观察结构。
- 团队无法学习 WatermelonDB 的编写器/模型/同步规则。
在 React Native 中 expo-sqlite, react-native-sqlite-storage, op-sqlite, react-native-quick-sqlite 还有类似的选项。特别是如果它是一个基于世博会的项目。 expo-sqlite在安装和兼容性方面可能会更简单。
WatermelonDB 何时更适合
相反,如果满足以下条件,WatermelonDB就有优势。
- 本地存储有数千到数万条数据。
- 应用程序执行速度很重要。
- 即使在离线状态下也必须创建/编辑数据。
- 需要与服务器同步更改。
- 必须从屏幕上的多个位置查看相同的数据并自动更新。
- 我想围绕应用程序域模型而不是 SQL 来组织代码。
如果用一行来概括的话,就是这样的。
SQLite 是一个“本地数据库引擎”,而 WatermelonDB 是“用于 React Native 应用程序的基于 SQLite 的数据层”。
同步结构
WatermelonDB并不是一个只提供本地DB的工具。它还提供同步功能,并考虑到离线优先的应用程序。不过,这里有一点不应该被误解。
WatermelonDB 不会为您创建服务器。
根据官方文档,WatermelonDB 提供了以下内容:
- 跟踪本地创建/编辑/删除的更改
synchronize()APIpullChanges,pushChanges同步流程的形式- 更改后端必须适应的对象结构
在前端,它看起来大致是这样的。
import { synchronize } from '@nozbe/watermelondb/sync'
export async function syncDatabase(database) {
await synchronize({
database,
pullChanges: async ({ lastPulledAt, schemaVersion, migration }) => {
const response = await fetch(
`https://api.example.com/sync?last_pulled_at=${lastPulledAt ?? ''}&schema_version=${schemaVersion}`
)
if (!response.ok) {
throw new Error(await response.text())
}
const { changes, timestamp } = await response.json()
return { changes, timestamp }
},
pushChanges: async ({ changes, lastPulledAt }) => {
const response = await fetch(
`https://api.example.com/sync?last_pulled_at=${lastPulledAt ?? ''}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(changes),
}
)
if (!response.ok) {
throw new Error(await response.text())
}
},
migrationsEnabledAtVersion: 1,
})
}
后端必须按以下格式交换更改:
{
"changes": {
"posts": {
"created": [
{ "id": "post_1", "title": "Hello", "body": "...", "is_pinned": false }
],
"updated": [],
"deleted": []
},
"comments": {
"created": [],
"updated": [],
"deleted": ["comment_1"]
}
},
"timestamp": 1710000000000
}
这里的关键是服务器时间戳和更改跟踪的一致性。官方文档也有pull端点 lastPulledAt 它解释了所有后续更改必须无一例外地返回,并且服务器时间必须设置在一致的基础上。如果这部分做得马虎,最终可能会出现“有些记录永远不会同步”的问题。
实际阻塞和解决方向
WatermelonDB 很强大,但它涉及到 React Native 原生模块、Babel、CocoaPods、Expo 和同步后端。实际开发过程中,经常会卡在下面这个点。
情况 1. 装饰器语法无法识别
症状通常如下所示:
SyntaxError: Support for the experimental syntax 'decorators' isn't currently enabled
首先,检查 Babel 设置。
npm ls @babel/plugin-proposal-decorators
.babelrc 或者 babel.config.js检查是否输入了遗留装饰器设置。
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
],
}
这里的一个常见错误是只查看 TypeScript 设置而忽略 Babel 设置。由于WatermelonDB示例使用了装饰器,因此必须在Metro/Babel管道中处理相应的语法。
案例 2. iOS 上 simdjson.h 或者,发生与 Pod 相关的构建错误。
在 iOS 构建中 simdjson 如果出现相关错误,请先检查Podfile和Pod安装状态。
cd ios
pod install
官方文档将指导您完成 Podfile。 simdjson 还要检查是否已输入设置。
pod 'simdjson', path: '../node_modules/@nozbe/simdjson', modular_headers: true
use_frameworks!使用的项目应该更加小心。 WatermelonDB官方安装文档中也给出了指导,大意是不推荐frameworks模式,并且相关的构建问题在GitHub issues中不断提及。该项目已经 use_frameworks!如果您依赖,那么在引入 WatermelonDB 之前首先在一个小示例分支上验证 iOS 构建会更安全。
案例 3. Expo Go 中未找到 Native 模块
Expo Go 不会随意包含任意原生模块。需要本机代码的库(例如 WatermelonDB)可能无法直接在 Expo Go 中运行。
示例症状类似于:
NativeModules.WMDatabaseBridge is not defined
在这种情况下,通常有三种选择。
1.使用Expo开发构建。 2. 检查配置插件或自定义本机设置。 3、如果需求简单 expo-sqlite将范围降低至
对于 Expo 项目,不要问“WatermelonDB 好用吗?”,而应该首先问“本机配置可以在当前的 Expo 工作流程中进行管理吗?”
案例4.React Native新架构兼容性不确定
React Native 0.7x之后,必须结合New Architecture、Bridgeless和最新的Expo SDK检查WatermelonDB的兼容性问题。与新架构、RN 0.76+ 和 Expo SDK 54+ 相关的疑问和问题发布在 GitHub issues 中。
如果是正在运行的app,建议按以下顺序检查。
npm view @nozbe/watermelondb version
npm view react-native version
另外,检查该项目的 RN/Expo 版本和 WatermelonDB GitHub 问题。在开启新架构之前,您必须首先验证本地数据库是否已正确初始化以及iOS/Android版本构建是否已完成。
案例 5. 重复或丢失同步
WatermelonDB同步并不仅仅以前端代码结束。后端 lastPulledAt 之后,必须准确返回更改。
如果出现问题,请检查以下内容:
- 我什么时候获取服务器时间戳?
- 是否有可能在拉取期间更改的数据可能会丢失?
- 删除的记录是否会记录到 ID 列表中?
- 您了解下次拉取时再次接收客户端推送的更改的结构吗?
- 发生冲突时服务器必须采取什么策略来失败/允许?
在同步是关键的应用程序中,后端同步协议设计可能比引入 WatermelonDB 更重要。
何时使用它,何时避免它?
何时推荐 WatermelonDB
- 我正在构建一个离线优先的应用程序。
- 本地数据很多,应用程序执行速度很重要。
- 需要一个关系数据模型。
- 数据更改应自动反映在多个屏幕上。
- 同步协议可以通过其自己的后端来实现。
- 团队可以处理 React Native 原生构建问题。
何时避免或推迟使用 WatermelonDB
- 只需要保存简单的设置。
- 它仅短暂缓存服务器 API 响应。
- 它必须仅使用Expo Go进行开发,并且本地构建配置很困难。
- 我正在积极使用最新的 React Native 新架构,但我没有时间验证兼容性。
- 有许多复杂的分析查询需要直接控制 SQL。
- 我无力自己设计同步后端。
结论
如果你把 WatermelonDB 的核心视为“一个让在 React Native 中使用 SQLite 更方便的库”,那就有点欠缺了。更准确地说 考虑大量本地数据、响应式 UI 和离线优先同步的数据框架。全部。
与 SQLite 相比,WatermelonDB 放弃了一些直接控制,但获得了应用程序级功能,例如模型驱动开发、可观察的 UI 更新和同步原语。因此,对于需要简单存储的应用程序来说,它是大材小用,但对于即使离线时数据仍不断积累和变化的应用程序来说,它非常适合。
如果你正在React Native项目中考虑WatermelonDB,你可以先这样判断。
1. 真的会有很多数据吗? 2. 是否需要离线创作/编辑? 3.我需要与服务器同步吗? 4. 您有时间验证 Expo/RN/iOS/Android 构建兼容性吗? 5. 应用程序域模型和响应式 UI 是否比直接控制 SQL 更重要?
如果您对大多数问题的回答是“是”,那么您可能想尝试一下 WatermelonDB。相反,如果只有两个或三个适用,则首先 expo-sqlite我 op-sqlite 简单地从相同的 SQLite 库开始并在数据结构增长时迁移到 WatermelonDB 的策略也是现实的。
参考资料
- WatermelonDB 官方文档: https://watermelondb.dev/docs
- WatermelonDB Installation: https://watermelondb.dev/docs/Installation
- WatermelonDB Schema: https://watermelondb.dev/docs/Schema
- WatermelonDB Model: https://watermelondb.dev/docs/Model
- WatermelonDB Querying: https://watermelondb.dev/docs/Query
- WatermelonDB CRUD: https://watermelondb.dev/docs/CRUD
- WatermelonDB Sync Intro: https://watermelondb.dev/docs/Sync/Intro
- WatermelonDB Sync Backend: https://watermelondb.dev/docs/Sync/Backend
- WatermelonDB GitHub: https://github.com/Nozbe/WatermelonDB
- npm @nozbe/watermelondb: https://www.npmjs.com/package/@nozbe/watermelondb
- 世博会 SQLite 文档: https://docs.expo.dev/versions/latest/sdk/sqlite/
- op-sqlite GitHub: https://github.com/OP-Engineering/op-sqlite
- react-native-sqlite-storage GitHub: https://github.com/andpor/react-native-sqlite-storage
相关文章
- React Native Nitro 和 TurboModule 总结:新架构中选择原生模块的标准: https://daily-it.duckdns.org/zh/2026/06/19/react-native-nitro-turbomodule-guide-zh/
- 什么是 SQLite?无服务器的基于文件的数据库的优点、局限性和实际用途: https://daily-it.duckdns.org/zh/2026/06/19/sqlite-local-database-guide-zh/