Realm 是一种移动端面向对象的 NoSQL 数据库,作为 SQLite 和 Core Data 在 iOS 和 Android 上的替代方案而开发。数据以自有格式存储,可直接访问内存中的对象,从而确保高读写速度。得益于响应式通知、通过 Realm Sync 的自动同步以及跨平台数据模型,Realm 被超过 10 亿台设备使用(MongoDB 数据,2025)。
要点
Realm 是一种面向对象的数据库,专为移动应用而创建。与 SQLite 不同,Realm 不使用 SQL 和关系模型——数据以活动对象(Live Objects)的形式存储,可以直接访问,无需中间 ORM 层。开发人员使用语言的原生对象(Swift、Kotlin、Dart)工作,这些对象会自动保存到数据库中。
Realm 于 2014 年作为初创公司 Realm Inc. 出现,并于 2019 年被 MongoDB Inc. 收购。此后,Realm 作为 MongoDB Realm 发展——是用于移动数据同步的统一 Atlas Device Sync 平台的一部分。本地 Realm 数据库保持免费和开源(Apache 2.0 许可证),而 Realm Sync(云同步)则通过订阅分发。
根据 MongoDB Developer Report(2025),Realm 被 15% 的移动应用用作主要本地存储。主要场景包括具有离线模式、复杂对象模型和设备间同步需求的应用,在这些场景中,Realm 在开发速度和对象操作便利性方面优于 SQLite。
Live Objects 每个 Realm 对象通过内存映射文件(memory-mapped file)连接到磁盘。在任何线程中更改对象会立即反映在所有其他线程中,无需手动通知。当数据通过 Realm 通知更改时,用户界面会自动重绘。Zero-copy Realm 不将数据从数据库复制到对象,对象本身就是内存中的数据。
Realm 核心 用 C++ 编写,并使用 B+ 树进行数据索引。与 SQLite 不同(其中每一行是关系表中的一条记录),Realm 将对象存储为图结构中的节点,节点之间有直接引用(前向指针)。对象之间的关系不是外键,而是直接指针,从而消除了对 JOIN 操作的需求。
Realm 文件(.realm 扩展名)是内存映射的——操作系统本身在访问时管理文件页到内存的加载。这使得 Realm 能够处理超过可用运行内存的数据库,并确保对于适合 RAM 的数据,读取延迟达到语言原生数据结构(Swift Array 或 Kotlin List)的水平。
内存映射文件 是 Realm 的关键技术。与将数据从数据库文件复制到语言对象(如 SQLite 通过 sqlite3_step + sqlite3_column_* 所做的那样)不同,Realm 将数据库文件直接映射到进程的地址空间。语言对象只是映射内存中数据的指针。更改对象会更改磁盘上的数据库,无需单独的保存调用。
| 特性 | Realm(零拷贝) | SQLite(复制) |
|---|---|---|
| 读取 | 直接内存访问(纳秒) | 复制到对象(微秒) |
| 写入 | 立即写入内存映射文件 | 使用 SQL INSERT/UPDATE 事务的 save() |
| 关系 | 直接指针(前向指针) | 外键 + JOIN |
| 内存消耗 | 文件 + 操作系统页面缓存 | 对象 + SQLite 页面缓存 |
| 活动对象 | 是(自动更新) | 否(需要新的 fetch) |
内存消耗 Realm 在主动读取时更高(整个文件或大部分映射到内存中),但在写入操作时更低,因为不需要为对象副本分配内存。对于移动设备上最大 1 GB 的数据库,内存映射方法比具有中间复制的 SQLite 提供更好的整体性能。
SQLite 是一个具有 SQL 和 ACID 事务的关系型数据库管理系统。Realm 是一个具有内存映射访问的对象 NoSQL 数据库。Core Data 是 Apple 在 SQLite 之上的 ORM 层。三种方法各有其应用领域和优势。Realm 在直接对象访问速度和响应性方面胜出,SQLite 在通用性和成熟度方面,Core Data 在与 Apple 生态系统的集成方面。
由于零拷贝访问,Realm 在读取操作上的性能比 SQLite 高 10-50%。在写入操作上,Realm 也更快,因为没有 SQL 语法解析和直接修改内存映射页面。然而,Realm 在处理大型数据库(>500 MB)时可能消耗更多运行内存,因为文件完全映射到地址空间。
| 标准 | Realm | SQLite | Core Data |
|---|---|---|---|
| 类型 | NoSQL 对象数据库 | 关系型 DBMS(SQL) | SQLite 之上的 ORM |
| 读取速度 | 高(零拷贝) | 中等 | 中等(ORM 开销) |
| 响应性 | Live Objects(内置) | 需要封装(Room/GRDB) | NSFetchedResultsController |
| 同步 | Realm Sync(MongoDB Atlas) | 需要自定义实现 | NSPersistentCloudKitContainer |
| 平台 | iOS、Android、Flutter、RN、Node.js | iOS、Android、Web、Desktop | 仅 iOS/macOS |
| 库大小 | ~4 MB | ~600 KB | 内置于 SDK |
Realm 和 SQLite 之间的选择通常取决于优先级:开发速度和响应性(Realm)与控制和通用性(SQLite)。Realm 特别适合 MVP 和原型,其中数据模型经常变化,快速获取实时 UI 更新很重要。SQLite/Room 更适合具有大量数据和复杂分析查询的成熟产品。
Realm Kotlin SDK 是适用于 Android 的官方库,用 Kotlin 编写(不是 Java SDK 的封装)。数据模型通过继承自 RealmObject 的类定义,使用 @PrimaryKey 注解表示唯一标识符。Realm Kotlin 支持 Kotlin Coroutines、Flow 和 KSP(Kotlin 符号处理)以在编译时生成代码。
RealmQuery 提供无需 SQL 的类型安全过滤 API。查询通过方法链构建:query → filter → sort → find。结果可以作为列表返回(加载到内存中)或作为 Flow 返回(响应式流,在数据更改时更新)。Realm Kotlin 还支持嵌套对象和列表(RealmList)。
Realm 的数据模型 定义为实现 RealmObject 接口的数据类。_id 字段用 @PrimaryKey 标记以进行唯一标识。“一对多”关系通过 RealmList 实现——一个其他 RealmObject 的列表。所有写入操作(create、update、delete)都在 write 事务块内执行。
class Project : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId().generate()
var name: String = ""
var tasks: RealmList<Task> = realmListOf()
}
class Task : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId().generate()
var title: String = ""
var isComplete: Boolean = false
}
val config = Realm.Configuration.Builder(
schema = setOf(Project::class, Task::class)
).build()
val realm = Realm.open(config)
realm.write { transactionRealm ->
val project = copyToRealm(Project().apply {
name = "Mobile App"
})
project.tasks.add(copyToRealm(Task().apply {
title = "Design UI"
}))
}
val projects: Flow<RealmResults<Project>> =
realm.query<Project>()
.sort(Project::name, Sort.ASCENDING)
.asFlow()
返回 Flow 的 查询会在 Realm 中的任何数据更改时自动发出新结果:添加、更新或删除 Project 或 Task。Flow 方法与 Compose 完美结合:ViewModel 中的 collectAsState() 在数据更改时自动重新组合 UI,无需手动更新列表适配器或使用 LiveData。
Realm Swift SDK 提供原生 Swift API,支持 async/await、Combine Publishers 和 Swift Concurrency。数据模型定义为继承自 Object 的类,使用 @Persisted 注解属性。Realm Swift 在更改时自动更新对象,通知(NotificationToken)允许订阅单个对象或集合的更改。
@ObservedRealmObject 和 @ObservedResults 是用于 SwiftUI 的属性包装器,可在 Realm 数据更改时自动重绘视图。@ObservedResults 处理查询结果,@ObservedRealmObject 处理特定对象。这两个属性在视图反初始化时取消订阅。
SwiftUI 集成 是 Realm SDK 的优势之一。@ObservedResults 属性包装器将 Realm 查询与 SwiftUI 中的显示连接起来。当任何任务更改时,SwiftUI 自动重新组合列表。realm.writeAsync 在后台线程上执行事务,不会阻塞 UI。
import RealmSwift
class TaskItem: Object, Identifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var title: String = ""
@Persisted var isDone: Bool = false
@Persisted var priority: Int = 0
}
struct TaskListView: View {
@ObservedResults(TaskItem.self,
sortDescriptor: SortDescriptor(["priority"]))
var tasks
var body: some View {
List {
ForEach(tasks) { task in
TaskRow(task: task)
}
}
Button("添加任务") {
let realm = try! Realm()
try! realm.write {
realm.add(TaskItem(value: ["title": "New task"]))
}
}
}
}
@ObservedResults 自动管理 Realm 查询的生命周期:创建视图时建立更改订阅,销毁时取消订阅。属性包装器接受可选谓词(NSPredicate)和排序。这消除了手动编写 fetch 查询、创建 ViewModel 和订阅 Realm 通知的需求。
离线应用 Realm 非常适合数据需要在没有互联网的情况下可用的场景。内置同步(Realm Sync 与 MongoDB Atlas)在连接到网络时自动解决冲突。应用继续使用本地数据工作,后台同步在有连接时更新数据。
响应式界面 Live Objects 和 Flow/Combine 通知使 Realm 成为数据频繁变化的应用的便捷选择:聊天、任务流、共享文档。UI 在添加、修改或删除数据时自动更新,无需手动调用 reloadData 或 invalidate。
跨平台项目 Realm 支持 Kotlin Multiplatform(KMP)、Flutter、React Native 和 Xamarin。数据模型定义一次并在所有平台上使用。这减少了代码重复,并保证了具有共享业务逻辑的 iOS 和 Android 应用之间数据模式的一致性。
Realm Sync 是内置于 MongoDB Atlas 的云服务。应用自动在用户设备和服务器之间同步数据。冲突根据 “最后写入获胜”策略或通过服务器上的自定义冲突解决函数解决。Realm Sync 支持部分同步(数据子集)以减少流量。
class SyncRepository {
private val app = App(
AppConfiguration(
appId = "my-realm-app-id"
)
)
suspend fun syncData() {
val user = app.login(Credentials.anonymous())
val config = SyncConfiguration.Builder(
user, setOf(Project::class)
).build()
val syncedRealm = Realm.open(config)
// 自动同步已激活
}
}
SyncConfiguration 配置与 MongoDB Atlas 的连接并定义要同步的模型集。用户认证后,Realm 自动从云端加载数据并将其与本地更改合并。同步在后台线程上运行,不需要手动调用——只需使用 SyncConfiguration 创建 Realm 实例即可。
常见问题
是的,本地 Realm 数据库完全免费(Apache 2.0 许可证)。通过 MongoDB Atlas 的 Realm Sync(云同步)是一种付费服务,包含在 Atlas Device Sync 订阅中。对于 Atlas 的免费层级,提供前 500 MB 数据和每月 100 万次操作。
可以,迁移可以通过将数据从 SQLite 导出为 JSON 并在应用首次加载时导入到 Realm 来实现。对于大量数据,使用流式迁移:并行向两个数据库写入数据,直到用户切换到应用的新版本,然后删除 SQLite 文件。
Realm Sync 默认使用 “最后写入获胜”策略——最后一次写入覆盖之前的写入。对于复杂冲突,在 MongoDB Atlas 服务器上配置自定义冲突解决函数,根据应用的业务逻辑合并来自不同设备的更改(例如合并值而不是替换)。
Realm 在数据库级别不支持 SQL 聚合(SUM、AVG、GROUP BY)。对于分析查询,建议通过 Realm Sync 将数据从 Realm 导出到 MongoDB Atlas,并通过 MongoDB 聚合管道执行聚合。对于简单计数,使用 realm.query<T>().count()。
Realm 默认不加密数据。要加密,请在配置中指定一个 64 字节的密钥:Realm.Configuration(encryptionKey: key)。加密使用 AES-256 + SHA-2 HMAC,并将操作开销增加 10-20%。没有加密的情况下,.realm 文件可以被任何有权访问文件系统的进程读取。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。