问题 commit_on_success如何处理嵌套?


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

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

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() 回滚?


9297
2018-01-31 14:33


起源



答案:


这是它的源代码: 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,可能支持 交易保存点  - 遗憾的是,它只在PostgreSQL后端可用,即使MySQL 5.x也支持它们。

编辑2012年4月10日:现在支持MySQL的Savepoint 在Django 1.4中可用

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


11
2018-01-31 15:58





为了获得对事务管理的更多控制,最好使用它 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()

在这里,您可以根据具体情况决定是否提交交易。


3
2017-09-11 22:33