【问题标题】:Realm migration race condition领域迁移竞争条件
【发布时间】:2016-01-27 18:17:16
【问题描述】:

如何保证在访问领域之前完成领域迁移?迁移领域数据库并开始读取/写入领域似乎存在竞争条件。这是我的问题:

目前,当用户启动应用程序时,我正在使用迁移关闭来设置领域配置。使用 RLMRealmConfiguration.setDefaultConfiguration(config) 设置领域配置后,我设置 RootViewController 并开始访问领域数据。

但是,当需要迁移时,有时会在迁移完成之前访问领域 - 导致崩溃(RLMException:对象已被删除或无效)。如果迁移是一个没有回调的异步任务,我们如何保证它在访问领域之前完成?

这是我的领域配置代码:

 class func SetRealmConfigurationForUser(userId: String) {
    let config = RLMRealmConfiguration.defaultConfiguration()

    // migration setup
    config.schemaVersion = 10
    config.migrationBlock = { migration, oldSchemaVersion in
        if oldSchemaVersion < 2 {
            migration.enumerateObjects(ContactUser.className()) { oldObject, newObject in
                // Change primary key from PhoneNumber to Phone_BaseId_Key
                let phone = oldObject?["PhoneNumber"]
                let baseId = oldObject?["BaseId"]

                newObject?["Phone_BaseId_Key"] = String(phone) + "_" + String(baseId)
            }
        }
        if oldSchemaVersion < 3 {
            migration.enumerateObjects(DigitsContact.className()) { oldObject, newObject in
                newObject?["ExternalId"] = ""
            }
        }
        if oldSchemaVersion < 9 {
            migration.deleteDataForClassName(DigitsContact.className())
            migration.deleteDataForClassName(Address.className())
            migration.deleteDataForClassName(Email.className())
            migration.deleteDataForClassName(PhoneNumber.className())
        }
    }

    // Use default directory, but replace filename with the userId
    config.path = (((config.path! as NSString).stringByDeletingLastPathComponent as NSString)
                                            .stringByAppendingPathComponent(userId) as NSString)
                                            .stringByAppendingPathExtension("realm")
    RLMRealmConfiguration.setDefaultConfiguration(config)

【问题讨论】:

    标签: objective-c swift migration realm race-condition


    【解决方案1】:

    根据Realm's Migrations docs,只有在使用设置了架构版本和迁移块的配置打开Realm时才会应用迁移:

    使用此配置创建 Realm 时,如果需要迁移,将应用迁移块将 Realm 更新到给定的架构版本。

    因此,如果您以异步方式调用SetRealmConfigurationForUser,任何并发的 Realm 访问都将使用以前的默认配置,并且看不到您正在定义的迁移块。

    执行迁移总是同步发生,通过在配置中使用迁移块隐式创建 Realm 或通过调用 RLMRealm.migrateRealm(_:) 显式进行。

    迁移完成后,所有其他 Realm 访问(读取和写入)都将被阻止。因此,只要在初始化任何 Realm 之前设置迁移块和配置,就不应该存在竞争条件。

    PS:当oldSchema &lt; 3 时,您在迁移块中做了很多浪费的工作,因为您将所有DigitsContact.ExternalId 属性设置为"",然后才删除所有DigitsContact 对象。只需删除 oldSchemaVersion &lt; 3 条件及其内容将导致相同的结果。

    PPS:您使用 Swift 的 Realm Objective-C 而不是 Realm Swift 有什么原因吗? Realm 有一个专用的 API,在 Swift 中使用起来更方便:https://realm.io/docs/swift/latest/

    【讨论】:

    • SetRealmConfigurationForUser 是同步调用的,因此必须在调用 Realm 之前访问它。我现在怀疑这是在单例中发生的,因为直到 SetRealmConfigurationForUser 之后才能访问 Realm。谢谢,这更有意义。另外,我使用的是 Obj-C Realm,因为该项目是 Swift 和 Obj-C 的混合体。
    • 澄清一下:即使 setDefaultConfiguration 在 migrationBlock 完成之前被调用,Realm 会阻止所有访问直到 migrationBlock 完成?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多