2011-01-31 10 views
11

Jestem nieco zdezorientowany tym, jak powinienem obsługiwać transakcje w konkretnej sytuacji.W jaki sposób uchwyt nest_on_success jest zagnieżdżony?

mam jakiś kod, który sprowadza się do tego:

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 

Chcę wiedzieć, co się dzieje, gdy process_post_reply() zawiedzie.

W jaki sposób uchwyt nest_on_success jest zagnieżdżony? Czy zrozumie, aby zatwierdzić każdy process_post_reply(), czy też jeden z nich nie powiedzie się wycofać cały process_post()?

Odpowiedz

11

Oto kod źródłowy to: https://github.com/django/django/blob/1.2.4/django/db/transaction.py#L286

I enter_transaction_management jest tak proste, jak wprowadzenie nowego trybu obsługi transakcji na stosie wątku.

W takim przypadku, jeśli wystąpi błąd process_post_reply() (to znaczy wystąpi wyjątek), transakcja zostanie wycofana w całości, a następnie wyjątek będzie rozprzestrzeniać się również w górę z process_post(), ale nic nie zostanie wycofane.

I nie, jeśli ktoś process_post_reply() nie wtedy cały process_post() nie jest przywracana - nie ma tam żadnej magii, tylko COMMIT i ROLLBACK na poziomie bazy danych, co oznacza, że ​​to, co dostaje przywracana jest tylko to, co zostało napisane do DB po ostatniej zatwierdzonej process_post_reply().

Podsumowując, myślę, że to, czego potrzebujesz jest tylko jeden commit_on_success() wokół process_post, ewentualnie poparte transaction savepoints - które niestety są dostępne tylko w PostgreSQL, MySQL 5.x choć wspiera je dobrze.

EDIT 10 kwietnia 2012: savepoint wsparcie dla MySQL jest teraz available in Django 1.4

EDIT 2 lipca 2014: zarządzanie transakcjami został całkowicie przepisany w Django 1.6 - https://docs.djangoproject.com/en/1.6/topics/db/transactions/ i commit_on_success została zaniechana.

3

Aby uzyskać większą kontrolę nad zarządzaniem transakcji, dobrze jest używać 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() 

Tutaj można zdecydować, w zależności od okoliczności popełnienia transakcję czy nie.

Powiązane problemy