Firebase Realtime Database 是谷歌的云 NoSQL 数据库,通过永久的 WebSocket 连接实时同步更改。数据以单个 JSON 树的形式存储,任何节点的任何更改都会立即传递给所有连接的客户端。根据 Google, 2026 的数据,Realtime Database 支持单个实例最多 20 万个并发连接。该服务每月提供 1 GB 存储和 10 GB 流量的免费限制。
要点
Firebase Realtime Database 是谷歌于 2012 年与 Firebase 一起推出的首批实时云数据库之一。它是一个 NoSQL 数据库,数据以可通过单个 URL 访问的单个 JSON 树形式存储。客户端 SDK(Android, iOS, Web)通过 WebSocket 订阅树的特定节点,并在每次数据更改时接收更新 — 无需 ping 服务器,也无需实现自己的推送机制。
最初的 Firebase 由 James Tamplin 和 Andrew Lee 于 2011 年创立,第一个产品就是 Realtime Database。在 2014 年被谷歌收购后(据 TechCrunch 报道 — 收购金额在 5000 万至 1 亿美元之间),该数据库被集成到 Google Cloud 中,并获得了显著更高的带宽。2017 年,谷歌宣布 Firestore 作为其演进替代品,但 Realtime Database 仍在积极维护和更新中。根据谷歌(2026 年)的数据,Realtime Database 仍被超过 150 万个活跃项目使用。
Spark 计划(免费)包括:1 GB 存储、每月 10 GB 下载数据、100 个并发连接以及一个区域的数据库支持。在 Blaze 计划(按需付费)中,需要为额外存储(1 美元/GB)、流量(0.12 美元/GB)和并发连接(每超出限制 10 万次收费 5 美元)付费。测试时还可以使用模拟模式 — firebase emulators:start — 在本地运行 Realtime Database,无需连接到云。
Realtime Database 没有表、集合或文档 — 一切都是一个 JSON 树,可通过 https://project-name-default-rtdb.firebaseio.com/ 形式的 URL 访问。树的每个键要么是最终值(字符串、数字、布尔值、null),要么是带有子键的嵌套节点。数据库引擎不支持 JOIN、子查询或聚合 — 查询始终返回一个节点及其所有子元素的内容。
由于 Realtime Database 中缺乏 JOIN,数据规范化 是强制性的。代替嵌套树(用户 → 其帖子列表),数据被分割成通过键引用的扁平列表。这是标准方法:数据被反规范化,以便读取一个节点不会拖累整个上下文。例如,聊天消息列表与用户配置文件分开存储,每个帖子仅包含作者的 ID,而不是其完整配置文件。
| 方法 | 结构示例 | 问题 |
|---|---|---|
| 嵌套 | users/{uid}/posts/{postId}/content | 读取 user 会加载所有帖子 |
| 扁平 | posts/{postId}/authorId + users/{uid}/name | 需要两次查询 |
| 反规范化 | posts/{postId}/authorName(复制) | 更新时重复 |
查询 在 Realtime Database 中使用 filter(orderByChild, orderByKey, orderByValue, limitToFirst, limitToLast, equalTo, startAt, endAt)执行。与 Firestore 不同,索引通过 Rules 部分(.indexOn)手动创建。如果未声明索引,带排序的查询将返回 PERMISSION_DENIED 错误。查询仅作用于一个字段 — 复合查询(按价格过滤 + 按日期排序)不受支持。对于复杂过滤,数据通常在不同节点中使用不同排序键重复。
Realtime Database 和 Firestore 之间的选择 是启动项目时常见的架构决策之一。谷歌推荐大多数新应用使用 Firestore,但在最小数据传输延迟至关重要的场景中,Realtime Database 仍然是最佳选择。
第一个场景 — 具有状态同步的多玩家游戏(国际象棋、纸牌游戏、实时动作)。Realtime Database 的延迟为 10-30 毫秒,而同一区域中 Firestore 为 50-100 毫秒。第二个场景 — 高频消息的聊天和通讯软件。Realtime Database 按数据量计费,而非按写入次数计费,这使得它在每秒超过 1 条消息的频率下比 Firestore 便宜得多。第三个场景 — 用户在线/离线存在状态(presence),Realtime Database 的 onDisconnect 处理程序允许在连接断开时原子性地设置状态。
根据谷歌(2026 年)的数据,约 15% 的新 Firebase 项目有意识地选择 Realtime Database — 当团队清楚了解延迟、数据结构和预算要求时。在其余 85% 的情况下,Firestore 是更安全的选择,因为它具有更好的可扩展性、更强大的查询和自动复制。
连接 Realtime Database 到 Android 应用是通过在 build.gradle 中添加 firebase-database-ktx 依赖来完成的。FirebaseDatabase 对象通过 getInstance(url) 可用 — 可以在一个 Firebase 项目中连接多个数据库。初始化后,SDK 会自动与服务器建立 WebSocket 连接并开始数据同步。
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.1.0"))
implementation("com.google.firebase:firebase-database-ktx")
}
// 使用自定义 URL 初始化
val database = FirebaseDatabase.getInstance(
"https://my-project-default-rtdb.firebaseio.com/"
)
val ref = database.getReference("chats")
Realtime Database 使用 DatabaseReference 对象进行所有操作。setValue() 将数据写入指定节点,完全替换其所有内容。push() 自动生成唯一键(基于时间戳)以将元素添加到列表 — 这是创建聊天消息、帖子和记录的标准方式。updateChildren() 在单个操作中以原子方式更改多个节点。addValueEventListener 订阅节点的更改,并在每次数据更新时接收回调。
data class Message(
val author: String = "",
val text: String = "",
val timestamp: Long = ServerValue.TIMESTAMP
)
class ChatRepository(private val ref: DatabaseReference) {
fun sendMessage(author: String, text: String) {
val msg = Message(author = author, text = text)
ref.child("messages").push().setValue(msg)
}
fun observeMessages(): Flow<List<Message>> = callbackFlow {
val listener = ref.child("messages")
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val messages = snapshot.children.mapNotNull { it.getValue(Message::class.java) }
trySend(messages)
}
override fun onCancelled(error: DatabaseError) {}
})
awaitClose { ref.removeEventListener(listener) }
}
}
同步机制 Realtime Database 基于 WebSocket 协议(以前是 long-polling)。客户端发送订阅特定节点的请求,服务器保持连接打开。每当订阅节点中的数据发生变化时,服务器会向客户端发送该节点的完整 JSON。客户端的 SDK 会自动更新本地状态并调用相应的回调(onDataChange)。
OnDisconnect — Realtime Database 的独特功能,Firestore 中没有。开发人员可以注册一个写入操作,该操作将在客户端连接断开时自动在服务器上执行。这用于存在状态:"user123/status": "online" 配合 onDisconnect.setValue("offline")。如果用户关闭了应用或失去了互联网连接,服务器将自动将状态设置为 "offline",最多在 3 分钟内(可在 Firebase 控制台中配置)。
Persistence 在 Realtime Database 中通过一行代码启用:FirebaseDatabase.getInstance().setPersistenceEnabled(true)。SDK 将所有订阅节点的最后状态缓存到磁盘(默认为最多 10 MiB,可配置到 100 MiB)。当连接丢失时,客户端继续使用缓存的数据工作,所有写入操作都会排队。当连接恢复时,SDK 将所有累积的更改按正确顺序(FIFO)发送到服务器。
根据谷歌(2026 年)的数据,启用持久性缓存的应用在连接断开时丢失用户数据的几率降低 40%。但是,如果客户端积累了超过 1000 个延迟操作,服务器可能会拒绝所有操作并要求完全同步 — 这是针对过时客户端的保护机制。
Security Rules 在 Realtime Database 中是一个 JSON 配置,描述谁以及在什么条件下可以在每个节点读取和写入数据。规则在谷歌服务器上运行,并在每次操作之前执行。默认情况下(在生产环境中),建议将规则设置为 "封闭" 模式 — 只有经过身份验证的用户才能访问。
Realtime Database 的规则以 JSON 格式编写,包含 .read、.write、.validate、.indexOn 部分。与 Firestore(使用 match 语法)不同,Realtime Database 使用反映数据结构的嵌套对象。条件检查 auth(身份验证)、data(现有数据)、newData(写入时的新数据)和 now(服务器时间)。验证规则(.validate)允许检查类型、值范围和数据结构。
{
"rules": {
"users": {
"$uid": {
".read": "auth.uid === $uid",
".write": "auth.uid === $uid",
".validate": "newData.hasChildren(['name', 'email'])"
}
},
"messages": {
".indexOn": ["timestamp"],
"$msgId": {
".read": true,
".write": "auth.uid !== null",
".validate": "newData.child('text').isString() && newData.child('text').val().length <= 500"
}
}
}
}
Realtime Database 的规则是级联继承的 — 如果顶层 .read = false,则所有子节点无论其自身规则如何都不可读取。Firebase 在控制台中提供了一个规则模拟器,可以在部署前使用不同的身份验证令牌测试操作。建议始终在模拟器中测试规则 — 规则中的错误可能会开放所有用户的私人数据访问权限。根据谷歌(2026 年)的数据,Firebase 项目中 40% 的数据泄露是由配置不当的安全规则引起的。
常见问题
单个数据库实例 最多 20 万 个并发连接。超过限制时,新连接将被阻止。对于扩展,使用分片到多个数据库。
使用 onDisconnect — 在连接断开时注册 "offline" 写入操作。服务器将在 WebSocket 断开时自动执行它。通过 .info/connected 单独跟踪连接。
检查 Security Rules 中的 .indexOn — 没有声明的索引,使用 orderByChild 的查询将返回 PERMISSION_DENIED。同时确保数据写入正确的节点,并且读取者具有 .read 权限。
Firebase Console 提供从 Realtime Database 到 Firestore 的 导出,一键完成。JSON 结构转换为集合和文档。对于自定义迁移,请使用 Admin SDK。
不,在 Realtime Database 中存储 密码 被谷歌的安全规则禁止。对于身份验证,请使用 Firebase Auth — 密码哈希存储在隔离的存储中,无法通过 Realtime Database SDK 访问。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。