写事务(write transaction)
Realm使用高效的storage engine来持久化对象。 您可以在 Realm 中创建对象、更新Realm 中的对象,以及最终从 Realm 中删除对象。 由于这些操作会修改 Realm 的状态,因此我们将其称为写入。
Realm 通过事务来处理写入。 事务是一系列读写操作,Realm 将其视为单个不可分割的操作。 换言之,事务是“全有或全无”:事务中的所有操作要么成功,要么事务中的所有操作都不生效。
所有写入都必须在事务中进行。
Realm 一次只允许一个打开的事务。 Realm 会阻止其他线程上的其他写入,直到打开的事务完成。 因此,在事务中从 Realm 读取值时,不存在争用情况。
完成事务后,Realm 要么提交事务,要么取消事务:
当 Realm提交事务时,Realm 会将所有更改写入磁盘。 对于同步 Realm,SDK 会将更改排队以便与 Atlas Device Sync 进行同步。
当 Realm取消写事务或事务中的操作导致错误时,所有更改都将被丢弃(或“回滚”)。
运行事务
Swift SDK 将每个事务表示为包含零个或多个读写操作的回调函数。 要运行事务,请定义事务回调并将其传递给 Realm 的 write方法。 在此回调中,您可以在 Realm 上自由创建、读取、更新和删除。 如果回调中的代码在 Realm 运行时抛出异常,Realm 将取消事务。 否则,Realm 会在回调后立即提交事务。
重要
并发问题
由于事务会相互区块,因此最好避免在用户界面线程和背景线程上同时打开事务。 如果您使用 Sync ,请完全避免在用户界面线程上打开事务,因为Realm在背景线程上处理同步。 如果背景ACID 事务阻止用户界面线程的ACID 事务,则应用可能会显示为无响应。
例子
以下代码展示了如何使用 Realm 的写入方法运行ACID 事务。 如果回调中的代码抛出异常, Realm将取消ACID 事务。 否则, Realm将提交ACID 事务。
// Open the default realm. RLMRealm *realm = [RLMRealm defaultRealm]; // Open a thread-safe transaction. [realm transactionWithBlock:^() { // ... Make changes ... // Realm automatically cancels the transaction in case of exception. // Otherwise, Realm automatically commits the transaction at the // end of the code block. }];
// Open the default realm. let realm = try! Realm() // Prepare to handle exceptions. do { // Open a thread-safe transaction. try realm.write { // Make any writes within this code block. // Realm automatically cancels the transaction // if this code throws an exception. Otherwise, // Realm automatically commits the transaction // after the end of this code block. } } catch let error as NSError { // Failed to write to realm. // ... Handle error ... }
接口驱动写入
Realm始终以异步方式传递通知,因此它们永远不会区块用户界面线程。 但是,在某些情况下,用户界面必须立即反映更改。 如果在写入的同时直接更新用户界面,则最终的通知可能会使更新量double 。 由于用户界面和支持数据存储之间的状态不一致,这可能会导致您的应用崩溃。 为避免这种情况,您可以在不向特定处理程序发送通知的情况下进行写入。 我们将这种类型的ACID 事务称为接口驱动的写入。
例子
假设我们决定手动管理表视图的数据源,因为我们的应用设计需要对用户界面驱动的表更新做出即时响应。 一旦用户将项目添加到表视图中,我们就会将其插入到数据源中,数据源会写入 Realm,但也会立即启动动画。 然而,当 Realm 稍后为此插入发送变更通知时,它表明已添加一个对象。 但我们已经为其更新了表视图! 我们可以使用接口驱动的写入来防止为该特定写入触发特定的通知处理程序,而不是编写复杂的代码来处理这种情况。
将细粒度集合通知与同步域 域一起使用时,接口驱动的写入(也称为静默写入)特别有用。 当您对当前用户的更新使用接口驱动的写入并立即更新用户界面时,同步进程可以使用标准通知来更新用户界面。