"transaction.atomic"与"transaction.commit_on_success"相同吗?

Jos*_*mit 61 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
Run Code Online (Sandbox Code Playgroud)

在上面的代码块中,commit_on_success使用单个事务完成所有工作my_function.

更换是否@transaction.commit_on_success@transaction.atomic在相同的行为结果?@transaction.atomic docs说:

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

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

kas*_*erd 61

根据我在这个主题上阅读的文档,这些装饰器嵌套时存在显着差异.

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

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

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

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

  • 不能为最里面的块提供耐久性.
  • 无法为最外面的块提供原子性.

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

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

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

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

  • "嵌套事务在不同的数据库中实现的方式不同.但是,它们的共同之处在于,在最外层事务提交之前,任何不相关的事务都不会看到更改.这意味着内部事务中的提交不需要持久更新数据库." ([维基百科(http://en.wikipedia.org/wiki/Nested_transaction)) (5认同)
  • 您会混淆*交易*和*块*。如果将事务定义为既具有原子性又具有持久性的事物(就您而言),则嵌套事务将不存在,而Django无法支持它们。但是您的回答和我的评论都是关于嵌套*块*的。Django确实支持这些。通过使用所有受支持的SQL数据库中存在的标准保存点功能来实现;而且这些嵌套块没有任何耐用性保证。它们是否持久存储在数据库中取决于它们所包含的事务的命运。 (2认同)

Kev*_*nry 46

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

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

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