2011-01-31 239 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的支持他們。

編輯2012年4月10日:MySQL的保存點支持現在available in Django 1.4

是編輯2014年7月2日:事務管理已經在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() 

在這裏,你可以根據情況決定,提交交易或不。