Rails 两者有什么关系 :dependent => :destroy 和 cascade delete/nullify/restrict

What Does Rails Do With Both :dependent => :destroy and cascade delete/nullify/restrict

我正在尝试决定如何最好地为我的 rails 应用程序设置(如果有的话)外键约束。我有一个模型 Response belongs_to 一个 Prompt。我想使用 :dependent => :destroy 对属于已删除 Prompt 的每个 Response 调用 destroy 并且我正在尝试决定我应该在我的外键上放置什么删除约束。

简而言之,我需要有关如何最好地利用依赖对象上的 destroy 方法和外键约束的建议,以确保 cruft 不会累积并反映所存储数据的逻辑结构。几个较早的问题,例如 Should I use ON DELETE CASCADE, :dependent => :destroy, or both? and Rails: delete cascade vs dependent destroy 询问哪个更好,但他们并没有真正说明这两个选择如何相互作用以及它们被触发的顺序或似乎在这一点上含糊不清。

在我看来,考虑因素似乎分为几部分:

  1. 是否 :dependent => :destroy 在从数据库中删除父对象之前先对依赖对象调用销毁,这样即使我使用级联删除,仍然会在这些对象上调用销毁?
  2. 是否 :dependent => :destroy 在从数据库中删除父对象之前(或在事务中)从数据库中删除依赖对象?换句话说,如果我将 cascade 设置为 nullify,数据库会在子对象被删除之前浪费地取消对它们的引用吗?

  3. 删除是由于原始销毁和链式 :dependent => :destroy 选项包含在事务中而发出的,或者不幸的是,如果我不设置级联删除,定时崩溃会在数据库中留下残骸?

  4. 如果我使用 restrict 作为外键 on_delete 选项,最终会 :dependent => :destroy 确保从数据库中删除父对象吗?

在事务中使用 dependent: :destroy rails 首先销毁所有依赖项,然后才删除记录本身。

可能存在竞争条件:如果在 rails 用于销毁但尚未删除父集合的读取集合之后添加了相关记录 - 它可能会被遗留下来。下面我们称这些为 "race condition records"。

  1. 是的,您可以使用 dependent: :destroyon delete cascade,这样可以在没有回调的情况下删除一些子项(竞争条件的)。如果回调是强制性的 - on delete restrict 加上一些锁定和显式删除子项可能会更好。 这有点像validates :some_field, uniqueness: true最好有唯一索引做后盾,只有数据库本身才能保证数据的一致性。

  2. 由于父项最后被删除,on delete nullify 不会妨碍(您将获得无效的竞争条件记录)

  3. 有事务包裹所有删除,只能留下竞争条件记录

  4. on delete restrict over dependent: :destroy 将仅针对竞争条件记录触发(并回滚整个事务),但如果没有竞争条件 - rails 将愉快地删除一切