66

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.commit_on_success导致@transaction.atomic相同的行为?@transaction.atomic 文档状态

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

我认为它们会导致相同的行为;正确的?

4

2 回答 2

62

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

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

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

  • 您希望块的内容是原子的,或者块内的所有内容都已提交,或者什么都不提交。
  • 您希望持久性,一旦您毫无例外地离开块,您就可以保证,您在块内写入的所有内容都是持久的。

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

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

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

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

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

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

于 2014-06-08T16:54:15.697 回答
49

是的。您应该atomic在以前使用过的地方使用commit_on_success

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

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

于 2014-02-18T19:26:06.087 回答