gpt4 book ai didi

ios - NSIncrementalStore 子类中的乐观锁定支持

转载 作者:可可西里 更新时间:2023-11-01 04:47:27 25 4
gpt4 key购买 nike

我正在实现一个自定义 NSIncrementalStore 子类,它使用关系数据库进行持久存储。我仍然挣扎的事情之一是对乐观锁定的支持。

(请随意跳过下面对我的问题的冗长描述)

我通过检查 Core Data 的 SQLite 增量存储生成的 SQL 日志来分析它是如何解决这个问题的,并得出以下结论:

  • 数据库中的每个实体表都有一个 Z_OPT 指示此实体(行)的特定实例已被修改的次数的列,从 1(初始插入)开始。
  • 每次修改托管对象时, Z_OPT 其相应数据库行中的值递增。
  • 存储维护 NSIncrementalStoreNode 实例的缓存(在 Core Data 文档中称为行缓存),每个实例都有一个 版本属性等于 Z_OPT 前一个返回的值 选择 更新 对托管对象行的 SQL 查询。
  • 当一个管理对象从 NSManagedObjectContext 返回时(例如通过在它上面执行 NSFetchRequest),MOC 创建这个对象的快照,其中包含这个 版本数字。
  • 当对象被修改或删除时,Core Data 通过比较缓存行和对象快照的版本来确保它没有在上下文之外被修改或删除。所有这一切都发生在 -保存:在对象所属的上下文上调用。如果版本不同,则根据设置的合并策略检测和处理合并冲突。

  • 保存 MOC 时, -newValuesForObjectWithID:withContext:error: 为每个修改/删除的对象调用方法,该对象又返回带有版本号的 NSIncrementalStoreNode。然后将此版本与快照的版本进行比较,如果它们不同,则保存会因适当的合并冲突而失败(至少在默认合并策略下)。

    这个简单的用例自 起在我的商店中正常工作-newValuesForObjectWithID:withContext:error: 如果对象在其他上下文中使用相同的存储实例同时修改,则首先检查行缓存就足够了。如果是这种情况,则缓存包含具有更高版本号的更新行,这足以检测冲突。

    但是我如何才能检测到基础数据库是否已在我的商店外被修改,可能是其他应用程序或其他商店实例使用相同的数据库文件?我知道这是一个不常见的边缘情况,但 Core Data 可以正确处理它,我更愿意这样做。

    Core Data 的存储使用这样的 SQL 查询来更新/删除对象的行:
    UPDATE ZFOO SET Z_OPT=Y, (...) WHERE (...) AND Z_OPT=X
    DELETE FROM ZFOO WHERE (...) AND Z_OPT=X

    在哪里:
    X - 商店最后知道的版本号(来自缓存)
    - 新版本号

    如果这样的查询失败(没有行受到影响),该行将在商店的缓存中更新,并将其版本与先前缓存的版本进行比较。

    我的问题是 :自定义 NSIncrementalStore 如何通知 Core Data 某些更新/删除/锁定的对象发生了乐观锁定失败?只有 store 才能知道当它处理传递给它的 NSSaveChangesRequest 时,它的 -executeRequest:withContext:error: 方法。

    如果底层数据库在 store 下没有改变,那么就会检测到冲突,因为 Core Data 调用了 -newValuesForObjectWithID:withContext:error: 在对存储执行保存更改请求之前,在每个修改/删除/锁定的对象上。我找不到任何方法让 NSIncrementalStore 通知 Core Data 发生了乐观锁定失败 它开始处理保存请求。有没有一些无证的方法可以做到这一点?在这种情况下,Core Data 似乎抛出了一些异常,然后神奇地将其转换为失败的保存请求,其中 NSError 列出了所有冲突。我只能通过从 返回 nil 来部分地模仿这一点。 -executeRequest:withContext:error: 并由我自己创建错误消息。我认为在这种情况下也必须有一种方法可以使用标准的 Core Data 冲突处理机制。

    最佳答案

    我意识到这不是您问题的答案,但我会尝试向您提供我对 CoreData 和与数据库相关性的看法:

    (一级缓存)
    NSPesistentStoreCoordinator + NSPersistentStore == 一个数据库连接

    (二级缓存)
    NSManagedObjectContext == 缓存在保存更改的连接上

    因此,据我所知,您的问题是您与商店有多个连接,每个连接都进行更改,但您没有对记录的中央版本控制。
    您的商店将收到 -executeRequest:withContext:error:NSSaveRequestType然后,您将负责验证记录版本是否匹配,如果您发现连接级别(级别 1)中存在冲突,则报告上下文(级别 2)和协调器之间的版本不匹配。
    您需要报告您的连接(级别 1)和您的商店之间的版本不匹配。
    为了能够做到这一点,您的商店必须报告所有与它的连接 (ConnectionManager) 上的更改,或者它可能会提供对其执行的更改的 Hook 。
    我不是 SQLite 专家,但 SQLite API 确实在该领域提供了一些东西:
    update hook
    commit hook
    changes
    total changes
    (我没有设置这些类型的钩子(Hook)的经验,但如果 CoreData 使用它们,它不会显示在调试日志中)

    您可以通过设置错误指针 (NSError**) 并将其内部数据设置为与 CoreData 协调器正在设置的数据相匹配来报告这些错误(创建合并冲突并根据需要设置其中的信息)

    注意乐观锁失败只会在-executeRequest:withContext:error:期间发生
    (除非您与商店有流氓连接,经理未跟踪的连接。
    为了支持这种行为,您的经理可能需要验证每条记录,因为它被提交以节省 [巨大的性能成本],或者使用一些 Hook 到最近对记录所做的更改
    )

    要处理到您的商店的多个连接,您可能需要拥有 NSIncrementalStoreNode 的共享缓存,由商店 url 键控:
    静止的 @{
    url1 : 实际缓存映射 1,
    url2 : 实际缓存映射2,
    ...
    }
    保存到商店的每个连接将再次验证商店 url 实际缓存。

    希望这对你有意义。

    关于ios - NSIncrementalStore 子类中的乐观锁定支持,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15821652/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com