Realm 是什么样的数据库?



Realm是什么样的数据库?是ORM吗?还是像对象数据库一样工作?也许数据库结构以某种方式影响设计过程?在设计 Realm 数据库时有什么细微差别吗?

我在这里问,因为我在官方网站上没有找到任何答案

不幸的是,我实际上并没有使用iOS版本,但我确实使用了Android版本,其功能集与iOS版本越来越相似,并且它们共享相同的core,并且它们更接近于通过object-store提供相同的统一行为。

因此,这个答案的大部分将基于 Swift API 文档。(领域斯威夫特 2.6.1)


默认情况下,Realm 是一个对象存储。从技术上讲,它将数据存储在架构中,其中架构由类定义,例如

// from https://realm.io/docs/swift/latest/#models
class Person: Object {
dynamic var name = ""
dynamic var birthdate = NSDate(timeIntervalSince1970: 1)
let dogs = List<Dog>()
}

Realm 的有趣之处在于它不是一个关系数据库;它直接存储对象。事实上,由 Realm 管理的对象(也就是通过查询 Realm 获得的对象,或者由 Realm 新创建的对象)直接映射到底层的 Realm 文件,并且不会将数据复制到字段中,访问器直接读取和写入 Realm 文件。

这种"直接访问"导致所有数据仅在访问时加载(延迟计算),因此不需要缓存托管对象(!

所有写入都是事务性的。在事务之外,不能修改托管的 RealmObjects。


在对象之间,可以有关系(链接):

// from https://realm.io/docs/swift/latest/#relationships
class Dog: Object {
// ... other property declarations
dynamic var owner: Person? // to-one relationships must be optional
}
class Person: Object {
// ... other property declarations
let dogs = List<Dog>() // to-many relationship
}

任何关系(to-one,to-multi)都有其相应的backlink,您可以将其定义为"链接到此对象的对象"。

// from https://realm.io/docs/swift/latest/#relationships
class Dog: Object {
dynamic var name = ""
dynamic var age = 0
let owners = LinkingObjects(fromType: Person.self, property: "dogs")
}

Realm 的托管对象是"实时的、不可变的数据视图"(从这里开始),它们会就地变异,你会通过notification token(从这里)收到关于它的变更通知。这同样适用于任何托管的 RealmObject,也适用于查询结果

这意味着,查询结果会自动异步计算,并且仅以延迟加载的方式从数据库中读取在给定索引处访问的元素!因此,不需要分页。

任何线程上的任何写入都会自动向与运行循环关联的线程发送通知,查询结果将自动更新,并调用更改侦听器(通知块)。

// from https://realm.io/docs/swift/latest/#collection-notifications
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
let results = realm.objects(Person.self).filter("age > 5")
// Observe Results Notifications
notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.tableView else { return }
switch changes {
case .initial:
// Results are now populated and can be accessed without blocking the UI
tableView.reloadData()
break
case .update(_, let deletions, let insertions, let modifications):
// Query results have changed, so apply them to the UITableView
tableView.beginUpdates()
tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }),
with: .automatic)
tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}),
with: .automatic)
tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }),
with: .automatic)
tableView.endUpdates()
break
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
fatalError("(error)")
break
}
}
}
deinit {
notificationToken?.stop()
}

最广为人知的限制是 RealmObjects、RealmResults 和 Realms不能在线程之间传递。(其他限制在这里)。

给定线程上的 RealmObject/RealmResults/Realm 只能在打开其相应 Realm 实例的线程上访问(阅读此处)。(例外是使用ThreadSafeReference在线程之间发送的 RealmObjects,请参阅此处)。

因此,后台线程需要自己的 Realm 实例,通常包装在autoreleasepool中,请参阅此处。

// from https://realm.io/docs/swift/latest/#using-a-realm-across-threads
DispatchQueue(label: "background").async {
autoreleasepool {
// Get realm and table instances for this thread
let realm = try! Realm()
// Break up the writing blocks into smaller portions
// by starting a new transaction
for idx1 in 0..<1000 {
realm.beginWrite()
// Add row via dictionary. Property order is ignored.
for idx2 in 0..<1000 {
realm.create(Person.self, value: [
"name": "(idx1)",
"birthdate": Date(timeIntervalSince1970: TimeInterval(idx2))
])
}
// Commit the write transaction
// to make this data available to other threads
try! realm.commitWrite()
}
}
}

相关内容

最新更新