【问题标题】:Is "transaction.atomic" same as "transaction.commit_on_success"?“transaction.atomic”和“transaction.commit_on_success”一样吗?
【发布时间】:2014-03-18 15:29:24
【问题描述】:

Django 1.6 提议 @transaction.atomic 作为从 1.5 开始对事务管理进行改造的一部分。

我有一个由 Django 管理命令调用的函数,该命令又由 cron 调用,即在这种情况下没有触发事务的 HTTP 请求。片段:

from django.db import transaction

@transaction.commit_on_success
def my_function():
    # code here

在上述代码块中,commit_on_success 使用单个事务处理在 my_function 中完成的所有工作。

用@transaction.atomic 替换@transaction.commit_on_success 会导致相同的行为吗? @transaction.atomicdocs state:

原子性是数据库事务的定义属性。原子 允许我们创建一个代码块,其中的原子性 数据库有保障。如果代码块成功 完成后,更改将提交到数据库。如果有一个 异常,更改将回滚。

我认为它们会导致相同的行为;对吗?

【问题讨论】:

  • 为了更清楚地说明这一点,有一个非常好的Djangocon talk 关于这个......

标签: django transactions django-1.6


【解决方案1】:

根据我阅读的有关该主题的文档,这些装饰器嵌套时存在显着差异。

嵌套两个 atomic 块与嵌套两个 commit_on_success 块的工作方式不同。

问题是您希望从这些块中获得两个保证。

  • 您希望块的内容是原子的,要么提交块内的所有内容,要么不提交任何内容。
  • 您希望获得持久性,一旦您毫无例外地离开该块,就可以保证您在该块中写入的所有内容都是持久的。

嵌套块时不可能同时提供这两种保证。如果在离开最里面的块之后但在离开最外面的块之前引发异常,您将不得不以两种方式之一失败:

  • 无法为最里面的方块提供耐久性。
  • 未能为最外层块提供原子性。

您可以在这里找到不同之处。使用commit_on_success 将为最里面的块提供持久性,但不会为最外面的块提供原子性。使用atomic 会给最外层的块提供原子性,但对最里面的块没有持久性。

在嵌套的情况下简单地引发异常可以防止您遇到问题。最里面的块总是会引发异常,因此它从不承诺任何持久性。但这失去了一些灵活性。

更好的解决方案是更详细地了解您的要求。如果您可以分别要求原子性和持久性,那么您可以执行嵌套。您只需要确保请求持久性的每个块都在请求原子性的块之外。在请求原子性的块内请求持久性将不得不引发异常。

atomic 应该提供原子性部分。据我所知,django 1.6.1 没有装饰器,它可以要求耐久性。我试着写了一个,posted它在codereview上。

【讨论】:

  • 感谢@kasperd,除了第一个答案提供的内容(我已标记为正确)之外,+1 提供了其他详细信息。
  • 这是一个有趣的分析,但您所说的持久性根本不是 SQL 数据库提供的保证。 commit_on_success 以您描述的方式工作的事实是一个错误(参见 ticket 2227,8 年前开放,仅在引入新的基于保存点的事务系统后才修复)。
  • "嵌套事务在不同数据库中的实现方式不同。但是,它们的共同点是在最外层事务提交之前,任何不相关的事务都不会看到更改。这意味着内部事务中的提交事务不需要持久更新数据库。” (Wikipedia)
  • @KevinChristopherHenry 持久性是数据库事务首先有意义的基本要求。不能保证事务持久的数据库大多是无用的。您是在暗示 django 一直在数据库本身中使用嵌套事务,这对我来说听起来很可疑。据我所知,postgres 不支持嵌套事务,如果 django 尝试这样做,我会认为这是一个错误。正如我所指出的,您首先需要将不同的保证分开来进行嵌套。
  • 你混淆了事务和blocks。如果您将事务定义为同时具有原子性和持久性(在您的意义上)的事物,那么嵌套事务将不存在,并且 Django 无法支持它们。但是你的回答和我的评论都是关于嵌套的blocks。 Django 确实支持这些;它通过使用存在于所有受支持的 SQL 数据库中的标准保存点功能来实现;并且那些嵌套块没有任何持久性保证。它们是否被持久化到数据库取决于它们所包含的事务的命运。
【解决方案2】:

是的。你应该在之前使用commit_on_success的地方使用atomic。

不过,由于新事务系统的设计更加稳健和一致,因此您可能会看到不同的行为。例如,如果您捕获数据库错误并尝试继续,您将看到 TransactionManagementError,而之前的行为是未定义的并且可能取决于大小写。

但是,如果你做事正确,一切都应该继续以同样的方式工作。

【讨论】:

    猜你喜欢
    • 2021-12-19
    • 2015-01-12
    • 1970-01-01
    • 2015-10-18
    • 2014-04-06
    • 2017-11-29
    • 2021-04-14
    • 2020-06-04
    • 2017-12-22
    相关资源
    最近更新 更多