Как commit_on_success обрабатывает вложенность? - PullRequest
11 голосов
/ 31 января 2011

Я немного озадачен тем, как мне следует обрабатывать транзакции в конкретной ситуации.

У меня есть код, сводящийся к следующему:

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 ]

11 голосов
/ 31 января 2011

Вот его исходный код: 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 также поддерживает их.

РЕДАКТИРОВАТЬ 10 ​​апреля 2012 : поддержка точек сохранения для MySQL теперь доступна в Django 1.4

РЕДАКТИРОВАТЬ 2 июля 2014 : Управление транзакциями полностью переписано в Django 1.6 - https://docs.djangoproject.com/en/1.6/topics/db/transactions/ и commit_on_success устарело.

3 голосов
/ 12 сентября 2012

Чтобы получить больше контроля над управлением транзакциями, хорошо использовать 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()

Здесь вы можете принять решение в зависимости от обстоятельств, совершать транзакции или нет.

...