“transaction.atomic”与“transaction.commit_on_success”相同吗?

时间:2014-02-18 17:33:51

标签: django transactions django-1.6

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 docs state

  

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

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

2 个答案:

答案 0 :(得分:59)

根据我在这个主题上阅读的文档,这些装饰器嵌套时会有很大的不同。

嵌套两个atomic块与嵌套两个commit_on_success块的效果不同。

问题在于您希望从这些块中获得两种保证。

  • 您希望块的内容是原子的,或者块中的所有内容都已提交,或者没有提交任何内容。
  • 你想要耐久性,一旦你离开了街区而没有例外,你可以保证,你在街区内写下的所有东西都是持久的。

嵌套块时无法提供两种保证。如果在离开最里面的块之后但在离开最外面的块之前引发异常,则必须以两种方式之一失败:

  • 无法为最里面的区块提供耐用性。
  • 无法为最外面的块提供原子性。

这是您找到差异的地方。使用commit_on_success将为最里面的块提供持久性,但是对于最外面的块没有原子性。使用atomic将为最外面的块提供原子性,但对最里面的块没有持久性。

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

更好的解决方案是更准确地了解您的要求。如果您可以单独询问原子性和耐久性,那么您可以执行嵌套。您只需确保请求持久性的每个块都超出请求原子性的块。在请求原子性的块内请求持久性将不得不引发异常。

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

答案 1 :(得分:44)

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

由于新的交易系统旨在更加健壮和一致,因此您可能会看到不同的行为。例如,如果您捕获数据库错误并尝试继续,您将看到TransactionManagementError,而之前的行为未定义且可能与案例有关。

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