2011-01-31 18 views
11

Sono un po 'confuso su come dovrei gestire le transazioni in una situazione particolare.In che modo commit_on_success gestisce l'annidamento?

Ho un po 'di codice che si riduce a questo:

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 

Voglio sapere che cosa succede se un process_post_reply() fallisce.

In che modo commit_on_success gestisce l'annidamento? Capirà di impegnare ogni process_post_reply() o se uno fallisce l'intero process_post() torna indietro?

risposta

11

Ecco il codice sorgente di esso: https://github.com/django/django/blob/1.2.4/django/db/transaction.py#L286

E enter_transaction_management è semplice come mettere nuova modalità di movimentazione sullo stack filo transazione.

Quindi, nel tuo caso, se process_post_reply() non riesce (ad esempio, si verifica un'eccezione), la transazione viene ripristinata nella sua interezza, quindi l'eccezione si propaga anche verso l'alto da process_post() ma non c'è nulla da ripristinare.

E no, se uno process_post_reply() fallisce allora l'intera process_post() non è da poco di nuovo - non c'è nessuna magia lì, solo COMMIT e ROLLBACK sul livello di database, il che significa che ciò che viene rollback è solo ciò che è stato scritto al DB dopo l'ultimo commit process_post_reply().

Riassumendo, penso che quello che ti serve è solo un singolo commit_on_success() intorno process_post, possibilmente supportata da transaction savepoints - che purtroppo sono disponibili solo in backend PostgreSQL, anche se MySQL 5.x li supporta pure.

EDIT 10 Apr 2012: supporto punto di salvataggio per MySQL è ora available in Django 1.4

EDIT 2 luglio 2014: Gestione delle transazioni è stato completamente riscritto in Django 1,6-https://docs.djangoproject.com/en/1.6/topics/db/transactions/ e commit_on_success è stato sconsigliato.

3

Per ottenere un maggiore controllo sulla gestione delle transazioni, è bene usare 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() 

Qui si può decidere a seconda delle circostanze, il commit della transazione oppure no.

Problemi correlati