Django

2013-02-12 5 views
6
में नेस्टेड @ transaction.commit_on_success के साथ कार्य करना

इस सरल उदाहरण पर विचार करें:Django

# a bank account class 
class Account: 
    @transaction.commit_on_success 
    def withdraw(self, amount): 
     # code to withdraw money from the account 

    @transaction.commit_on_success 
    def add(self, amount): 
     # code to add money to the account 

# somewhere else 
@transaction.commit_on_success 
def makeMoneyTransaction(src_account, dst_account, amount): 
    src_account.withdraw(amount) 
    dst_account.add(amount) 

(https://code.djangoproject.com/ticket/2227 से लिया गया)

एक अपवाद Account.add() में जन्म देती हैं, तो Account.withdraw() में लेन-देन अभी भी प्रतिबद्ध है और पैसे की जाएगी खो जाएगा, क्योंकि Django वर्तमान में नेस्टेड लेनदेन संभाल नहीं करता है।

Django को पैच लगाने के बिना, हम कैसे सुनिश्चित कर सकते हैं कि प्रतिबद्धता डेटाबेस को भेजी जाती है, लेकिन केवल तभी जब @transaction.commit_on_success सजावट के तहत मुख्य कार्य अपवाद उठाए बिना खत्म हो जाता है?

मैं इस स्निपेट में आया: http://djangosnippets.org/snippets/1343/ और ऐसा लगता है कि यह काम कर सकता है। क्या कोई कमी है मुझे पता होना चाहिए कि क्या मैं इसका उपयोग करता हूं?

यदि आप मदद कर सकते हैं तो अग्रिम में बहुत धन्यवाद।

पीएस मैं कॉपी करने कर रहा हूँ पहले से दृश्यता के प्रयोजनों के लिए कोड का टुकड़ा उद्धृत:

def nested_commit_on_success(func): 
    """Like commit_on_success, but doesn't commit existing transactions. 

    This decorator is used to run a function within the scope of a 
    database transaction, committing the transaction on success and 
    rolling it back if an exception occurs. 

    Unlike the standard transaction.commit_on_success decorator, this 
    version first checks whether a transaction is already active. If so 
    then it doesn't perform any commits or rollbacks, leaving that up to 
    whoever is managing the active transaction. 
    """ 
    commit_on_success = transaction.commit_on_success(func) 
    def _nested_commit_on_success(*args, **kwds): 
     if transaction.is_managed(): 
      return func(*args,**kwds) 
     else: 
      return commit_on_success(*args,**kwds) 
    return transaction.wraps(func)(_nested_commit_on_success) 
+0

मुझे यह भी यकीन नहीं है कि यह कोड स्निपेट काम करेगा। ऐसा लगता है कि अब 4 साल का है, और कोई कह रहा है कि यह यहां काम नहीं करता है: http://djangosnippets.org/snippets/2515/ – alexpirine

उत्तर

5

इस स्निपेट के साथ समस्या यह है कि यह तुम वापस रूप में अच्छी तरह बाहरी लेन-देन वापस रोलिंग के बिना एक आंतरिक लेनदेन रोल करने की क्षमता नहीं देता है। उदाहरण के लिए:

@nested_commit_on_success 
def inner(): 
    # [do stuff in the DB] 

@nested_commit_on_success 
def outer(): 
    # [do stuff in the DB] 
    try: 
     inner() 
    except: 
     # this did not work, but we want to handle the error and 
     # do something else instead: 

     # [do stuff in the DB] 

outer() 

उपरोक्त उदाहरण में, यहां तक ​​कि अगर inner() एक अपवाद को जन्म देती है, उसकी सामग्री वापस लुढ़का नहीं किया जाएगा।

आंतरिक "लेनदेन" के लिए आपको savepoint की आवश्यकता है। अपने कोड के लिए, यह इस प्रकार दिखाई देंगे:

# a bank account class 
class Account: 
    def withdraw(self, amount): 
     sid = transaction.savepoint() 
     try: 
      # code to withdraw money from the account 
     except: 
      transaction.savepoint_rollback(sid) 
      raise 

    def add(self, amount): 
     sid = transaction.savepoint() 
     try: 
      # code to add money to the account 
     except: 
      transaction.savepoint_rollback(sid) 
      raise 

# somewhere else 
@transaction.commit_on_success 
def makeMoneyTransaction(src_account, dst_account, amount): 
    src_account.withdraw(amount) 
    dst_account.add(amount) 

Django 1.6 के रूप में, atomic() डेकोरेटर ठीक करता है: यह डेकोरेटर के बाहरी उपयोग के लिए एक सौदे का उपयोग करता है, और किसी भी आंतरिक उपयोग एक savepoint उपयोग करता है।

+1

धन्यवाद, आप वास्तव में समाधान सुरक्षित दिखते हैं। मुझे आशा है कि Django @atomic decorator पेश करेगा जो भविष्य में रिलीज में सेवपॉइंट्स का उपयोग करता है। इस बीच, मैं मेरा उपयोग जारी रखूंगा क्योंकि इसका उपयोग करना आसान है। यदि आप उप-विधियों से उठाए गए अपवादों को अनदेखा नहीं करते हैं तो यह अभी भी कार्य करने जा रहा है। – alexpirine

2

Django 1.6 @atomic प्रस्तुत करता है, जो वास्तव में मैं देख रहा था!

न केवल यह "नेस्टेड" लेनदेन का समर्थन करता है, बल्कि यह पुराने, कम शक्तिशाली, सजावटी को भी बदल देता है। और विभिन्न Django ऐप्स में लेनदेन प्रबंधन के लिए एक अद्वितीय और लगातार व्यवहार करना अच्छा होता है।