为什么ActiveRecord提供.delete_all而不是.truncate?

10

我觉得需要手动执行SQL语句才能使用TRUNCATE命令有点奇怪。DHH是在保护我免受某些不好的影响吗?

4个回答

10

在某些数据库上使用 TRUNCATE 不会触发触发器。对每一行使用 DELETE 仍然会触发触发器。此外,TRUNCATE 无法回滚,因此如果您在事务中执行了 .destroy_all,即使尝试回滚,它也会删除所有数据。

所以,是的,您受到了对 truncate 的保护。


为什么它们没有一个 truncate 方法,如果您试图从事务内调用它,则会引发错误?这样做在我看来可以满足 @seamusabshere 的要求,但仍然可以减轻最糟糕的情况。在解释为什么会引发错误时,文档将被迫解释风险。这只是我的意见,价值 $0.02。 - Isaac Betesh
1
我相信TRUNCATE在MySQL和PostgreSQL中是事务安全的。 - jsears

3

假设您使用的是MySQL或Postgre而不是不支持TRUNCATE的SQlite3,您可以将以下方法添加到您的模型中。

def self.truncate
  self.connection_pool.with_connection { |c| c.truncate(table_name) }
end

请注意,这不会触发ActiveRecord回调。有更好的方法可以实现这一点,而且不会将您的代码与特定的数据库实现绑定在一起,但即使这样做,也比自己编写SQL要好些。

1

TRUNCATE有许多用途,但在我看来,这里给出的答案非常不充分。以Postgres为例:

  • TRUNCATE在某些RDBMS中绝对是事务安全的,正如jsears已经指出的那样。它可以回滚,至少在Postgres中是这样的。Rails难道不应该是数据库无关的,并允许这种操作吗?
  • TRUNCATE还将执行Postgres中的BEFORE TRUNCATEAFTER TRUNCATE触发器。如果你期望在TRUNCATE上触发DELETE触发器,那么这是你的设计错误!
  • TRUNCATEDELETE快得多,特别是对于大型数据集,因为它只是一个简短的DDL语句。
  • 在Postgres的MVCC架构中,TRUNCATE删除所有索引和表膨胀。

基于这些原因,我认为Rails不支持TRUNCATE是很荒谬的。不,我不认为给出的理由是好的。


-3

看一下Model.destroy_all和active record: dependent => :destroy关系。如果您没有指定:dependent => :destory,一些默认值是将关系设置为null而不是销毁记录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接