Firebase Realtime Database 是一种云 JSON 实时数据库,由 Google 于 2012 年推出,专为移动和 Web 应用程序而设计。所有数据存储在一个大型 JSON 树中,并通过 WebSocket 连接在连接的客户端之间实时同步。根据官方文档 Firebase, 2025,Realtime Database 可支持多达 200,000 个并发连接,每秒最多支持 1000 次并发写入。该数据库无需服务器基础设施,并提供适用于 iOS、Android、Web 和服务端平台的 SDK。
要点
Firebase Realtime Database 是一种云 NoSQL 数据库,它实时存储和同步所有已连接客户端之间的数据。该数据库于 2012 年以 Firebase 名义推出(在被 Google 收购之前),成为移动开发者的第一个实时云数据库。数据以 JSON 格式呈现,并组织成层次化树结构,每个节点具有唯一路径。
Realtime Database 的核心价值在于内置同步功能。当应用程序在任何设备上更改数据时,所有其他已连接的客户端都会通过持久连接立即收到更新。这使开发者无需自行实现同步机制、WebSocket 服务器或 REST API 即可在客户端之间传输数据。
该数据库为所有主流平台提供 SDK:Android(Java、Kotlin)、iOS(Swift、Objective-C)、Web(JavaScript)以及通过 Admin SDK 的服务端环境。据 Google 数据,Realtime Database 在全球超过 150 万个活跃 Firebase 项目中被使用。尽管出现了更现代的 Firestore,Realtime Database 仍然是数据结构简单项目的热门选择。
与关系型数据库不同,Realtime Database 不使用表和行。所有数据形成一个单一的 JSON 树,类似于嵌套的 JavaScript 对象。例如,要存储用户及其消息,会创建一个层次结构:users/userId/name 和 messages/messageId/text。树中的每个路径都是一个字符串,可以直接通过该路径访问数据。
{
"users": {
"user1": {
"name": "伊万·彼得罗夫",
"email": "ivan@example.com"
},
"user2": {
"name": "玛丽亚·索科洛娃",
"email": "maria@example.com"
}
},
"messages": {
"-Nabc123": {
"text": "你好!",
"userId": "user1"
}
}
}
一个重要特性是深层嵌套会影响性能。当应用程序读取特定路径下的数据时,它会加载该路径的所有子节点。因此,建议尽可能设计扁平的数据结构,避免嵌套超过 3-4 层。为了解决这个问题,可以使用数据反规范化——在不同树节点中重复信息。
Realtime Database 和 Firestore 通常被比较为 Google 提供的两种云实时数据库。它们之间的选择取决于项目的具体要求:查询复杂性、所需的一致性和预期负载。了解每个数据库的优势有助于做出正确的架构决策。
Realtime Database 的主要优势是低同步延迟。由于所有数据都存储在一个 JSON 树中,没有额外的抽象层,因此同步速度比 Firestore 更快。对于更新交付速度至关重要的应用程序(聊天、在线游戏、协同编辑系统),Realtime Database 可能是更合适的选择。
Realtime Database 更适合数据结构简单且更新频率高的场景。典型示例包括:聊天、实时点赞、输入指示器、用户在线状态。对于原型和预算有限的项目,这也是一个不错的选择,因为定价基于数据量而非操作数量。
另一方面,对于需要复杂查询(多字段过滤、排序、聚合)的应用程序,Firestore 提供了更强大的功能。Realtime Database 仅支持单参数过滤,无法同时对多个字段进行排序。如果项目计划在客户端进行复杂的数据分析,Firestore 将是更实用的选择。
Realtime Database 使用持久的 WebSocket 连接进行双向数据同步。当客户端在特定路径上调用 setValue 或 updateChildren 时,数据通过开放通道发送到 Firebase 服务器。服务器应用更改并在毫秒内向所有订阅的客户端广播更新。每个连接由唯一的会话密钥标识。
订阅机制通过 listeners 工作。开发者可以订阅特定节点的更改(addListenerForSingleValueEvent)或接收持续更新(addValueEventListener)。每次数据更改时,都会调用 onDataChange 回调,并返回指定路径的完整数据快照。这与 Firestore 不同,后者只返回更改的文档——在 Realtime Database 中,始终加载节点的所有数据。
Realtime Database 通过磁盘缓存支持 Android 和 iOS 上的离线模式。SDK 保存数据的本地副本,并在无网络时继续处理写入操作。当连接恢复时,所有累积的更改将发送到服务器。冲突解决采用最后写入获胜策略,但开发者可以通过 ServerValue.TIMESTAMP 实现自定义逻辑来解决冲突。
val database = FirebaseDatabase.getInstance()
val myRef = database.getReference("messages")
// 写入数据
myRef.push().setValue(
hashMapOf(
"text" to "新消息",
"timestamp" to ServerValue.TIMESTAMP
)
)
// 持续更新读取
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val data = snapshot.getValue()
Log.d("TAG", "数据:$data")
}
override fun onCancelled(error: DatabaseError) {
Log.w("TAG", "错误:${error.message}")
}
})
为优化流量和性能,建议在需要跟踪特定子节点更改时使用 child listeners 而非 value listeners。ChildEventListener 为添加、更改、删除和移动子元素提供单独的回调,从而更精确地控制 UI 更新,避免在每次数据更改时重新绘制所有列表项。
Realtime Database 使用声明式规则语言来控制数据访问。规则描述了谁可以读取和写入 JSON 树中每个路径的数据。它们在每次请求前在 Firebase 服务器上进行验证,无需服务器端授权逻辑。规则支持变量、内置对象和函数,以实现灵活的访问配置。
默认情况下,所有用户对数据库的访问都是被拒绝的。开发者通过使用 ".read" 和 ".write" 规则在树的不同级别逐步开放访问。条件可以通过 auth 变量检查身份验证、请求类型(读/写)以及通过 data 对象检查现有数据。此外,规则还支持通过 newData 对象对写入数据进行验证。
{
"rules": {
"users": {
"$uid": {
// 只有所有者可以读取自己的数据
".read": "$uid === auth.uid",
// 只有所有者可以写入
".write": "$uid === auth.uid",
// 写入时的字段验证
".validate": "newData.hasChildren(['name', 'email'])"
}
},
"messages": {
// 任何经过身份验证的用户都可以读取
".read": "auth !== null",
// 只有经过身份验证的用户才能写入
".write": "auth !== null",
".indexOn": ["timestamp"]
}
}
}
规则还通过 ".indexOn" 指令支持数据索引。如果没有索引,使用排序的查询(orderByChild)将被拒绝或执行效率低下。索引在需要进行特定字段排序的每个路径上指定。规则是级联的:更深层的规则覆盖父级规则,如果某个级别没有访问规则,则根据父级规则确定允许或拒绝。
Realtime Database 支持五种数据类型:String、Number、Boolean、Map(对象)和 List(数组)。嵌套深度限制为 32 层,单个节点的最大大小不得超过 256 MB。为了高效使用数据库,建议设计扁平的数据结构,并使用反规范化来避免加载大量数据的深层查询。
让我们看一个在 Android 应用中集成 Realtime Database 的实际示例,用于用户状态(在线/离线)。该应用将显示用户列表及其当前状态,并实时更新。示例使用 Firebase Authentication 进行用户身份验证,并使用协程进行异步操作。
首先,在应用模块的 build.gradle 文件中添加 firebase-database-ktx 依赖。库版本通过 Firebase BoM 管理,以确保所有组件的兼容性。添加依赖后,需要在 Application 类中初始化 Firebase,或通过 ViewModel 中的惰性初始化来完成。
dependencies {
implementation platform("com.google.firebase:firebase-bom:33.0.0")
implementation "com.google.firebase:firebase-database-ktx"
implementation "com.google.firebase:firebase-auth-ktx"
}
配置完成后,创建一个用于处理用户数据的仓库。每个用户在 /users/{uid} 树中表示为一个节点,包含 name、email 和 status 字段。为了跟踪状态,使用 onDisconnect——一种 Firebase 的特殊机制,可在客户端连接断开时自动执行写入操作。这确保了在应用关闭或网络丢失时,用户状态会自动切换到"离线",而无需客户端额外编写代码。
class PresenceRepository {
private val database = FirebaseDatabase.getInstance()
private val auth = FirebaseAuth.getInstance()
private val presenceRef = database
.getReference("presence")
fun trackPresence() {
val uid = auth.currentUser?.uid ?: return
val userRef = presenceRef.child(uid)
userRef.onDisconnect().setValue("offline")
userRef.setValue("online")
}
fun getPresenceStream(): Flow<Map<String, String>> =
presenceRef.snapshotFlow()
.map { snapshot ->
(snapshot.value as? Map<*, *>)
?.mapKeys { it.key.toString() }
?.mapValues { it.value.toString() }
?: emptyMap()
}
}
示例的关键元素是 onDisconnect。这种机制允许设置一个写入操作,该操作将在客户端连接断开时在服务器上执行。在这种情况下,当用户断开连接时,其状态会自动设置为"离线",无需处理应用关闭事件。如果应用意外终止,Firebase 将自动执行 onDisconnect 操作,其他用户将看到正确的状态。
常见问题
Realtime Database 将数据存储在一个 JSON 树中,提供更低的同步延迟。Firestore 使用文档集合,支持复杂查询和强一致性。Realtime Database 更适合简单的聊天和状态应用,而 Firestore 适用于数据结构复杂且需要分析的应用。
Realtime Database 单个节点的最大大小为 256 MB。嵌套深度限制为 32 层。单个 Firebase 项目可以创建多个 Realtime Database 实例(Spark 计划最多 5 个,Blaze 计划最多 100 个),从而可以将数据分布到不同的实例中。
Realtime Database 与 Firebase Authentication 集成。安全规则中有一个 auth 变量,包含已验证用户的 uid。开发者可以在 JSON 树的各个节点级别控制访问,检查数据所有者的 uid 是否匹配。匿名和未验证用户的 auth 值为 null。
是的,Realtime Database 通过 runTransaction 方法支持事务。事务确保单个节点的读-改-写操作的原子性。当发生并发更改时,事务会使用最新数据重试。这对于计数器、评分和其他需要数据一致性的场景非常有用。
是的,Realtime Database 支持 Android 和 iOS 上的离线模式。SDK 在本地缓存数据,并在无网络时继续处理写入操作。当连接恢复时,所有累积的更改将与服务器同步。要启用离线模式,可在目标节点上使用 keepSynced(true) 方法。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。