销毁和删除的区别

Posted

技术标签:

【中文标题】销毁和删除的区别【英文标题】:Difference between Destroy and Delete 【发布时间】:2014-05-10 13:10:03 【问题描述】:

有什么区别

@model.destroy@model.delete

例如:

Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all

我使用一个或另一个真的很重要吗?

【问题讨论】:

【参考方案1】:

基本上“删除”直接向数据库发送查询以删除记录。在这种情况下,Rails 不知道它正在删除的记录中有哪些属性,也不知道是否有任何回调(例如 before_destroy)。

“destroy”方法获取传递的 id,使用“find”方法从数据库中获取模型,然后对其调用 destroy。这意味着回调被触发。

如果您不希望触发回调或希望获得更好的性能,您可能需要使用“删除”。否则(大部分时间)你会想要使用“destroy”。

【讨论】:

【参考方案2】:

是的,这两种方法有很大区别 如果您希望在不调用模型回调的情况下快速删除记录,请使用 delete_all

如果您关心模型回调,请使用 destroy_all

来自官方文档

http://apidock.com/rails/ActiveRecord/Base/destroy_all/class

destroy_all(conditions = nil) public

通过实例化每条记录来销毁匹配条件的记录 并调用它的destroy方法。执行每个对象的回调 (包括:依赖关联选项和 before_destroy/after_destroy 观察者方法)。返回集合 被毁坏的物品;每个都将被冻结,以反映 不应进行任何更改(因为它们无法持久化)。

注意:每条记录的实例化、回调执行和删除 一次删除多条记录时可能会很耗时。它 每条记录至少生成一个 SQL DELETE 查询(或者可能更多, 强制执行您的回调)。如果你想快速删除很多行, 不用担心它们的关联或回调,使用 delete_all 而是。

【讨论】:

【参考方案3】:

当您在 ActiveRecord 对象上调用 destroydestroy_all 时,将启动 ActiveRecord 'destruction' 过程,它会分析您要删除的类,确定它应该对依赖项执行什么操作,然后运行通过验证等。

当您在对象上调用deletedelete_all 时,ActiveRecord 仅尝试对数据库运行DELETE FROM tablename WHERE conditions 查询,不执行其他ActiveRecord 级别的任务。

【讨论】:

【参考方案4】:

基本上destroy 会在模型上运行任何回调,而delete 不会。

来自Rails API:

ActiveRecord::Persistence.delete

删除数据库中的记录并冻结此实例以反映不应进行任何更改(因为它们无法持久化)。返回冻结的实例。

在记录的主键上使用 SQL DELETE 语句简单地删除该行,并且不执行任何回调。

要强制执行对象的 before_destroy 和 after_destroy 回调或任何 :dependent 关联选项,请使用 #destroy。

ActiveRecord::Persistence.destroy

删除数据库中的记录并冻结此实例以反映不应进行任何更改(因为它们无法持久化)。

有一系列与销毁相关的回调。如果 before_destroy 回调返回 false,则取消操作并且 destroy 返回 false。有关详细信息,请参阅 ActiveRecord::Callbacks。

【讨论】:

您好@user740584 - 感谢您的回答。 “在模型上运行任何回调”是什么意思? @BKSpureon 他的意思是 ActiveRecord::Callbacks:api.rubyonrails.org/classes/ActiveRecord/Callbacks.html。一个这样的回调是model#before_destroy,它可用于在某些条件下停止最终的destroy() 调用。【参考方案5】:

delete 只会从 db 中删除当前对象记录,但不会从 db 中删除其关联的子记录。

destroy 将从 db 中删除当前对象记录以及从 db 中关联的子记录。

它们的使用真的很重要:

如果您的多个父对象共享公共子对象,则在特定父对象上调用destroy 将删除在其他多个父对象之间共享的子对象。

【讨论】:

出色的答案。谢谢。我要补充一点,据我所知,术语是孩子们被“杀死”。残忍的杀婴。 在生产环境中的大多数情况下,您都希望使用 'destroy' 不,这没有必要。 我认为您应该为 destroy 使用的词是 descendants,而不是 children:根据文档,destroy “创建一个新的从属性中提取对象,然后对其调用destroy。” rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy【参考方案6】:

已经有很多答案了;想继续前进。

docs:

对于 has_many,destroy 和 destroy_all 将始终调用要删除的记录的 destroy 方法,以便运行回调。但是 delete 和 delete_all 将根据 :dependent 选项指定的策略进行删除,或者如果没有给出 :dependent 选项,那么它将遵循默认策略。默认策略是什么都不做(保留设置了父 id 的外键),除了 has_many :through,默认策略是 delete_all(删除连接记录,不运行它们的回调)。

delete 措辞对ActiveRecord::Association.has_manyActiveRecord::Base 的作用不同。对于后者,删除将执行SQL DELETE 并绕过所有验证/回调。前者将根据传递给关联的:dependent 选项执行。但是,在测试过程中,我发现了以下副作用,即只为 delete 而不是 delete_all 运行回调

dependent: :destroy 示例:

class Parent < ApplicationRecord
   has_many :children,
     before_remove: -> (_)  puts "before_remove callback" ,
     dependent: :destroy
end

class Child < ApplicationRecord
   belongs_to :parent

   before_destroy ->  puts "before_destroy callback" 
end

> child.delete                            # Ran without callbacks
Child Destroy (99.6ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 21]]

> parent.children.delete(other_child)     # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 22]]

> parent.children.delete_all              # Ran without callbacks
Child Destroy (1.0ms)  DELETE FROM "children" WHERE "children"."parent_id" = $1  [["parent_id", 1]]

【讨论】:

【参考方案7】:

例子:

Class User
  has_many :contents, dependent: :destroy
end

user = User.last
user.delete -> only user
user.destroy -> delete user , and contents of user

delete 将从数据库中删除当前记录(无回调)

destroy 将删除当前记录和关联记录(有回调)

delete_alldestroy_all 也一样

【讨论】:

以上是关于销毁和删除的区别的主要内容,如果未能解决你的问题,请参考以下文章

queue.wait() 和等待缓冲区销毁有啥区别

queue.wait() 和等待缓冲区销毁有啥区别

带头链表的创建和销毁

删除/销毁和编辑路由

Spring bean初始化与销毁的几种方式和区别

销毁对象在java中怎么用