commit_on_success如何处理嵌套?

时间:2011-01-31 14:33:10

标签: database django django-orm

我对如何处理特定情况下的交易感到有点困惑。

我有一些可以归结为此的代码:

from django.db import transaction

@transaction.commit_on_success
def process_post():
    #do stuff with database
    for reply in post_replies:
        process_post_reply(reply)

@transaction.commit_on_success
def process_post_reply(reply):
    #do stuff with database

我想知道如果process_post_reply()失败会发生什么。

commit_on_success如何处理嵌套?是否理解提交每个process_post_reply()或者如果一个失败则整个process_post()回滚?

2 个答案:

答案 0 :(得分:11)

以下是它的源代码:https://github.com/django/django/blob/1.2.4/django/db/transaction.py#L286

enter_transaction_management就像在线程堆栈上放置新的事务处理模式一样简单。

因此,在您的情况下,如果process_post_reply()失败(即发生异常),那么事务将完全回滚,然后异常从process_post()向上传播但是没有任何内容回滚。

不,如果一个process_post_reply()失败,那么整个process_post()都没有被回滚 - 那里没有魔法,只有数据库级别的COMMIT和ROLLBACK,这意味着回滚的是只有在最后一次提交process_post_reply()之后写入数据库的内容。

总结一下,我认为您需要的内容只是commit_on_success()周围process_post,可能由transaction savepoints支持 - 遗憾的是,它只在PostgreSQL中可用后端,即使MySQL 5.x也支持它们。

编辑2012年4月10日:现在对MySQL的Savepoint支持available in Django 1.4

EDIT 2014年7月2日:事务管理已在Django 1.6中完全重写 - https://docs.djangoproject.com/en/1.6/topics/db/transactions/commit_on_success已被弃用。

答案 1 :(得分:3)

要获得对事务管理的更多控制,最好使用transaction.commit_manually()

@transaction.commit_on_success
def process_post(reply):
    do_stuff_with_database()
    for reply in post_replies:
        process_post_reply(transaction_commit_on_success=False)

def process_post_reply(reply, **kwargs):
    if kwargs.get('transaction_commit_on_success', True):
        with transaction.commit_manually():
            try:
                do_stuff_with_database()
            except Exception, e:
                transaction.rollback()
                raise e
            else:
                transaction.commit()
    else:
        do_stuff_with_database()

您可以根据情况决定是否提交交易。