2011-01-31 3 views
11

Я немного смущен тем, как я должен обрабатывать транзакции в конкретной ситуации.Как 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()?

ответ

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

Подводя итог, Я думаю, что вам нужно только один commit_on_success() вокруг process_post, возможно, при поддержке transaction savepoints - которые, к сожалению, доступны только в PostgreSQL бэкэндом, даже если MySQL 5.x поддерживает их.

EDIT 10 апреля 2012: Savepoint поддержка MySQL теперь available in Django 1.4

EDIT 2 июля 2014: Управление транзакциями была полностью переписана в Django 1.6 - https://docs.djangoproject.com/en/1.6/topics/db/transactions/ и commit_on_success устарела.

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() 

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

Смежные вопросы