Django 2.1 - Database transactions

डेटाबेस लेनदेन




django

डेटाबेस लेनदेन

Django आपको यह नियंत्रित करने के कुछ तरीके देता है कि डेटाबेस लेनदेन कैसे प्रबंधित किया जाता है।

डेटाबेस लेनदेन का प्रबंधन

Django का डिफ़ॉल्ट लेनदेन व्यवहार

Django का डिफ़ॉल्ट व्यवहार ऑटोकॉमिट मोड में चलना है। प्रत्येक क्वेरी तुरंत डेटाबेस के लिए प्रतिबद्ध है, जब तक कि कोई लेनदेन सक्रिय न हो। विवरण के लिए नीचे देखें

Django, ORM संचालन की अखंडता की गारंटी देने के लिए स्वचालित रूप से लेन-देन या बचत बिंदुओं का उपयोग करता है, जिनके लिए कई प्रश्नों की आवश्यकता होती है, विशेष रूप से delete() और update() क्वेरी।

Django के TestCase वर्ग भी प्रदर्शन कारणों के लिए एक लेनदेन में प्रत्येक परीक्षण लपेटता है।

HTTP अनुरोधों के लिए लेनदेन को बांधना

वेब पर लेन-देन को संभालने का एक सामान्य तरीका प्रत्येक अनुरोध को लेनदेन में लपेटना है। प्रत्येक डेटाबेस के कॉन्फ़िगरेशन में ATOMIC_REQUESTS को True सेट करें ATOMIC_REQUESTS लिए आप इस व्यवहार को सक्षम करना चाहते हैं।

यह इस तरह काम करता है। व्यू फ़ंक्शन को कॉल करने से पहले, Django एक लेनदेन शुरू करता है। यदि प्रतिक्रिया समस्याओं के बिना निर्मित होती है, तो Django लेनदेन करता है। यदि दृश्य अपवाद बनाता है, तो Django लेन-देन को वापस ले लेता है।

आप आमतौर पर atomic() संदर्भ प्रबंधक के साथ, अपने व्यू कोड में सेवपॉइंट्स का उपयोग करके सूक्ष्मता प्रदर्शन कर सकते हैं। हालाँकि, दृश्य के अंत में, या तो सभी या कोई भी परिवर्तन प्रतिबद्ध नहीं होंगे।

चेतावनी

जबकि इस लेन-देन मॉडल की सादगी आकर्षक है, यह ट्रैफ़िक बढ़ने पर इसे अक्षम भी बनाता है। हर दृश्य के लिए एक लेन-देन खोलना कुछ ओवरहेड है। प्रदर्शन पर प्रभाव आपके आवेदन के क्वेरी पैटर्न पर और आपके डेटाबेस को लॉक करने में कितनी अच्छी तरह से निर्भर करता है।

प्रति-अनुरोध लेनदेन और स्ट्रीमिंग प्रतिक्रियाएं

जब कोई दृश्य एक StreamingHttpResponse लौटाता है, तो प्रतिक्रिया की सामग्री को पढ़कर अक्सर सामग्री उत्पन्न करने के लिए कोड निष्पादित किया जाएगा। चूंकि दृश्य पहले ही वापस आ चुका है, ऐसे कोड लेनदेन के बाहर चलता है।

आम तौर पर, एक स्ट्रीमिंग प्रतिक्रिया उत्पन्न करते समय डेटाबेस को लिखना उचित नहीं है, क्योंकि प्रतिक्रिया भेजने के लिए शुरू करने के बाद त्रुटियों को संभालने का कोई समझदार तरीका नहीं है।

व्यवहार में, यह सुविधा नीचे वर्णित atomic() डेकोरेटर में हर दृश्य फ़ंक्शन को लपेटती है।

ध्यान दें कि लेन-देन में केवल आपके दृश्य का निष्पादन संलग्न है। मिडलवेयर लेन-देन के बाहर चलता है, और इसलिए टेम्पलेट प्रतिक्रियाओं का प्रतिपादन करता है।

जब ATOMIC_REQUESTS सक्षम होता है, तब भी विचारों को लेन-देन में चलने से रोकना संभव है।

non_atomic_requests(using=None) [source]

यह डेकोरेटर दिए गए दृश्य के लिए ATOMIC_REQUESTS के प्रभाव को नकार देगा:

from django.db import transaction

@transaction.non_atomic_requests
def my_view(request):
    do_stuff()

@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

यह केवल तभी काम करता है जब यह स्वयं दृश्य पर लागू हो।

लेनदेन को स्पष्ट रूप से नियंत्रित करना

Django डेटाबेस लेनदेन को नियंत्रित करने के लिए एक एकल एपीआई प्रदान करता है।

atomic(using=None, savepoint=True) [source]

एटॉमिसिटी डेटाबेस लेनदेन की परिभाषित संपत्ति है। atomic हमें कोड का एक ब्लॉक बनाने की अनुमति देता है जिसके भीतर डेटाबेस पर परमाणुता की गारंटी होती है। यदि कोड का ब्लॉक सफलतापूर्वक पूरा हो गया है, तो परिवर्तन डेटाबेस के लिए प्रतिबद्ध हैं। यदि कोई अपवाद है, तो परिवर्तन वापस किए जाते हैं।

atomic ब्लॉकों को नस्ट किया जा सकता है। इस स्थिति में, जब कोई आंतरिक ब्लॉक सफलतापूर्वक पूरा हो जाता है, तो इसके प्रभावों को अभी भी वापस ले जाया जा सकता है अगर बाद के बिंदु पर बाहरी ब्लॉक में एक अपवाद उठाया जाता है।

atomic एक decorator रूप में उपयोग करने योग्य है:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

और एक संदर्भ प्रबंधक के रूप में :

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

एक प्रयास में atomic को लपेटना / ब्लॉक को छोड़कर अखंडता त्रुटियों की प्राकृतिक हैंडलिंग के लिए अनुमति देता है:

from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()

    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()

    add_children()

इस उदाहरण में, भले ही generate_relationships() अखंडता बाधा को तोड़कर डेटाबेस त्रुटि का कारण बनता है, आप add_children() में क्वेरी निष्पादित कर सकते हैं, और create_parent() से परिवर्तन अभी भी हैं। ध्यान दें कि handle_exception() में generate_relationships() किसी भी ऑपरेशन को पहले ही सुरक्षित रूप से रोल किया जाएगा जब handle_exception() कहा जाता है, इसलिए यदि आवश्यक हो तो अपवाद हैंडलर भी डेटाबेस पर काम कर सकता है।

atomic अंदर अपवादों को पकड़ने से बचें!

atomic ब्लॉक से बाहर निकलते समय, Django यह देखता है कि क्या यह सामान्य रूप से बाहर निकलता है या एक अपवाद के साथ यह निर्धारित करने के लिए कि क्या प्रतिबद्ध या वापस रोल करना है। यदि आप एक atomic ब्लॉक के अंदर अपवादों को पकड़ते हैं और संभालते हैं, तो आप Django से इस तथ्य को छिपा सकते हैं कि कोई समस्या हुई है। इससे अप्रत्याशित व्यवहार हो सकता है।

यह ज्यादातर DatabaseError और इसके उपवर्गों जैसे कि IntegrityError लिए एक चिंता का विषय है। इस तरह की त्रुटि के बाद, लेनदेन टूट गया है और Django atomic ब्लॉक के अंत में एक रोलबैक प्रदर्शन करेगा। यदि आप रोलबैक होने से पहले डेटाबेस क्वेरी को चलाने का प्रयास करते हैं, तो Django एक TransactionManagementError बढ़ाएगा। जब ORM- संबंधित सिग्नल हैंडलर अपवाद उठाता है, तो आप इस व्यवहार का सामना भी कर सकते हैं।

डेटाबेस त्रुटियों को पकड़ने का सही तरीका एक atomic ब्लॉक के आसपास है जैसा कि ऊपर दिखाया गया है। यदि आवश्यक हो, तो इस उद्देश्य के लिए एक अतिरिक्त atomic ब्लॉक जोड़ें। इस पैटर्न का एक और फायदा है: यह स्पष्ट रूप से परिसीमन करता है कि अपवाद होने पर कौन से ऑपरेशन वापस किए जाएंगे।

यदि आप कच्चे SQL प्रश्नों द्वारा उठाए गए अपवादों को पकड़ते हैं, तो Django का व्यवहार अनिर्दिष्ट और डेटाबेस-निर्भर है।

लेन-देन वापस करते समय आपको मैन्युअल रूप से मॉडल स्थिति को वापस करने की आवश्यकता हो सकती है।

लेन-देन रोलबैक होने पर किसी मॉडल के फ़ील्ड का मान वापस नहीं किया जाएगा। यह तब तक असंगत मॉडल स्थिति का कारण बन सकता है जब तक कि आप मूल फ़ील्ड मानों को मैन्युअल रूप से पुनर्स्थापित न करें।

उदाहरण के लिए, MyModel को एक active क्षेत्र के साथ दिया गया है, यह स्निपेट सुनिश्चित करता है कि if obj.active अंत में active if obj.active चेक सही मूल्य का उपयोग करता है, तो लेन-देन में True को active करते हुए:

from django.db import DatabaseError, transaction

obj = MyModel(active=False)
obj.active = True
try:
    with transaction.atomic():
        obj.save()
except DatabaseError:
    obj.active = False

if obj.active:
    ...

परमाणुता की गारंटी के लिए, atomic कुछ एपीआई को निष्क्रिय कर देता है। atomic ब्लॉक के भीतर डेटाबेस कनेक्शन के ऑटोकॉमिट स्टेट को कमिट करने, रोल करने या बदलने का प्रयास एक अपवाद को बढ़ाएगा।

atomic एक तर्क using है जो एक डेटाबेस का नाम होना चाहिए। यदि यह तर्क प्रदान नहीं किया जाता है, तो Django "default" डेटाबेस का उपयोग करता है।

हुड के तहत, Django के लेनदेन प्रबंधन कोड:

  • सबसे बाहरी atomic ब्लॉक में प्रवेश करते समय एक लेनदेन खोलता है;
  • एक आंतरिक atomic ब्लॉक में प्रवेश करते समय एक बचत बिंदु बनाता है;
  • एक आंतरिक ब्लॉक से बाहर निकलने पर सेवपॉइंट पर रिलीज़ या रोल करता है;
  • सबसे बाहरी ब्लॉक से बाहर निकलने पर लेन-देन को वापस करता है या रोल करता है।

आप savepoint तर्क के निर्माण को आंतरिक खंडों के लिए सहेज कर सकते हैं। यदि कोई अपवाद होता है, तो Django रोलबैक का प्रदर्शन करेगा जब एक है, और सबसे बाहरी ब्लॉक अन्यथा है, तो एक savepoint के साथ पहले मूल ब्लॉक को बाहर निकालता है। बाहरी लेनदेन से अभी भी परमाणु की गारंटी है। इस विकल्प का उपयोग केवल तभी किया जाना चाहिए जब सेव पॉइंट्स का ओवरहेड ध्यान देने योग्य हो। इसमें ऊपर वर्णित त्रुटि हैंडलिंग को तोड़ने का दोष है।

ऑटोकॉमिट बंद होने पर आप atomic उपयोग कर सकते हैं। यह केवल सबसे बाहरी ब्लॉक के लिए भी, बचत बिंदुओं का उपयोग करेगा।

प्रदर्शन के विचार

खुले लेनदेन में आपके डेटाबेस सर्वर के लिए प्रदर्शन लागत होती है। इस ओवरहेड को कम करने के लिए, अपने लेनदेन को यथासंभव कम रखें। यह विशेष रूप से महत्वपूर्ण है यदि आप Django के अनुरोध / प्रतिक्रिया चक्र के बाहर लंबे समय से चल रही प्रक्रियाओं में atomic() का उपयोग कर रहे हैं।

Autocommit

क्यों Django autocommit का उपयोग करता है

SQL मानकों में, प्रत्येक SQL क्वेरी एक लेनदेन शुरू करती है, जब तक कि कोई पहले से ही सक्रिय न हो। इस तरह के लेन-देन को स्पष्ट रूप से प्रतिबद्ध या पीछे ले जाना चाहिए।

यह एप्लिकेशन डेवलपर्स के लिए हमेशा सुविधाजनक नहीं होता है। इस समस्या को कम करने के लिए, अधिकांश डेटाबेस एक ऑटोकॉमिट मोड प्रदान करते हैं। जब स्वतः पूर्ण चालू होता है और कोई लेन-देन सक्रिय नहीं होता है, तो प्रत्येक SQL क्वेरी अपने लेनदेन में लिपटी रहती है। दूसरे शब्दों में, न केवल प्रत्येक ऐसी क्वेरी एक लेन-देन शुरू करती है, बल्कि लेनदेन भी स्वचालित रूप से प्रतिबद्ध या वापस लुढ़क जाता है, इस पर निर्भर करता है कि क्वेरी सफल हुई।

PEP 249 , Python Database API Specification v2.0, शुरू में बंद होने के लिए ऑटोकॉमिट की आवश्यकता होती है। Django इस डिफ़ॉल्ट को ओवरराइड करता है और ऑटोकॉमिट को चालू करता है।

इससे बचने के लिए, आप लेनदेन प्रबंधन को निष्क्रिय कर सकते हैं, लेकिन यह अनुशंसित नहीं है।

लेनदेन प्रबंधन को निष्क्रिय करना

आप किसी कॉन्फ़िगरेशन के लिए AUTOCOMMIT को अपने कॉन्फ़िगरेशन में सेट करके डेटाबेस के लिए Django के लेनदेन प्रबंधन को पूरी तरह से अक्षम कर सकते हैं। यदि आप ऐसा करते हैं, तो Django ऑटोकॉमिट को सक्षम नहीं करेगा, और कोई भी कमिट नहीं करेगा। आपको अंतर्निहित डेटाबेस लाइब्रेरी का नियमित व्यवहार मिलेगा।

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

करने के बाद कार्रवाई करना

कभी-कभी आपको वर्तमान डेटाबेस लेनदेन से संबंधित कार्रवाई करने की आवश्यकता होती है, लेकिन केवल तभी जब लेनदेन सफलतापूर्वक होता है। उदाहरणों में एक Celery कार्य, एक ईमेल अधिसूचना या कैश अमान्य शामिल हो सकता है।

Django कॉलबैक फ़ंक्शंस को पंजीकृत करने के लिए on_commit() फ़ंक्शन प्रदान करता है on_commit() लेनदेन के सफलतापूर्वक संपन्न होने के बाद निष्पादित किया जाना चाहिए:

on_commit(func, using=None) [source]

किसी भी फ़ंक्शन (जो कोई तर्क नहीं लेता है) को on_commit() :

from django.db import transaction

def do_something():
    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.

transaction.on_commit(do_something)

आप अपने कार्य को लंबोदर में भी लपेट सकते हैं:

transaction.on_commit(lambda: some_celery_task.delay('arg1'))

आपके द्वारा पास किए जाने वाले फ़ंक्शन को एक काल्पनिक डेटाबेस लिखने के तुरंत बाद बुलाया जाएगा, जहां on_commit() कहा जाता है, सफलतापूर्वक प्रतिबद्ध होगा।

यदि आप सक्रिय लेनदेन नहीं करते हैं तो on_commit() कॉल करें, कॉलबैक तुरंत निष्पादित किया जाएगा।

यदि वह काल्पनिक डेटाबेस लिखने के बजाय वापस लुढ़का हुआ है (आमतौर पर जब एक atomic() ब्लॉक में एक अखंडित अपवाद को उठाया जाता है), तो आपका फ़ंक्शन त्याग दिया जाएगा और कभी भी कॉल नहीं किया जाएगा।

Savepoints

Savepoints (यानी नेस्टेड atomic() ब्लॉक) को सही तरीके से संभाला जाता है। अर्थात्, एक on_commit() एक नेस्टेड atomic() ब्लॉक के बाद पंजीकृत किया जाता है, बाहरी लेनदेन के प्रतिबद्ध होने के बाद कॉल किया जाएगा, लेकिन यह नहीं कि क्या उस सेवपॉइंट का कोई रोलबैक या लेन-देन के दौरान कोई पिछला सेवपॉइंट हुआ है

with transaction.atomic():  # Outer atomic, start a new transaction
    transaction.on_commit(foo)

    with transaction.atomic():  # Inner atomic block, create a savepoint
        transaction.on_commit(bar)

# foo() and then bar() will be called when leaving the outermost block

दूसरी ओर, जब एक सेवपॉइंट को वापस रोल किया जाता है (एक अपवाद उठाए जाने के कारण), तो आंतरिक कॉल करने योग्य नहीं कहा जाएगा:

with transaction.atomic():  # Outer atomic, start a new transaction
    transaction.on_commit(foo)

    try:
        with transaction.atomic():  # Inner atomic block, create a savepoint
            transaction.on_commit(bar)
            raise SomeError()  # Raising an exception - abort the savepoint
    except SomeError:
        pass

# foo() will be called, but not bar()

फाँसी का आदेश

किसी दिए गए लेन-देन के लिए ऑन-कम फ़ंक्शन को उसी क्रम में निष्पादित किया जाता है जिस क्रम में वे पंजीकृत थे।

उपवाद सम्भालना

यदि किसी दिए गए लेन-देन के भीतर एक ऑन-कम फ़ंक्शन एक अनकहा अपवाद को उठाता है, तो उसी लेन-देन में बाद में पंजीकृत फ़ंक्शन नहीं चलेंगे। यह, निश्चित रूप से, एक ही व्यवहार है जैसे कि आपने on_commit() बिना कार्यों को क्रमिक रूप से निष्पादित किया है।

निष्पादन की समय सीमा

आपके कॉलबैक को एक सफल कमिटमेंट के बाद निष्पादित किया जाता है, इसलिए कॉलबैक में विफलता के कारण लेनदेन वापस नहीं होगा। लेन-देन की सफलता पर उन्हें सशर्त निष्पादित किया जाता है, लेकिन वे लेनदेन का हिस्सा नहीं हैं। इच्छित उपयोग के मामलों (मेल नोटिफिकेशन, सेलेरी कार्यों आदि) के लिए, यह ठीक होना चाहिए। यदि यह नहीं है (यदि आपकी अनुवर्ती कार्रवाई इतनी महत्वपूर्ण है कि इसकी विफलता का मतलब लेनदेन की विफलता स्वयं होना चाहिए), तो आप on_commit() हुक का उपयोग नहीं करना चाहते हैं। इसके बजाय, आप मानसोपग टू-फ़ेज़ कमिट प्रोटोकॉल सपोर्ट और पायथन डीबी-एपीआई विनिर्देश में वैकल्पिक टू-फ़ेज़ कमिट एक्सटेंशन्स जैसे दो-चरण की प्रतिबद्धता चाहते हैं।

कॉलबैक तब तक नहीं चलाया जाता है जब तक कि कमिटमेंट के बाद ऑटोकॉमिट को रिस्टोर नहीं किया जाता है (क्योंकि अन्यथा कॉलबैक में किए गए कोई भी प्रश्न एक निहित लेनदेन खोलते हैं, जिससे कनेक्शन को ऑटोकॉमिट मोड में वापस जाने से रोका जा सकता है)।

जब ऑटोकॉमिट मोड में और एक atomic() ब्लॉक के बाहर, फ़ंक्शन तुरंत चलेगा, तो प्रतिबद्ध नहीं।

ऑन-फंक्शन फ़ंक्शन केवल ऑटोकॉमिट मोड और atomic() (या ATOMIC_REQUESTS ) लेनदेन एपीआई के साथ काम करते हैं। on_commit() अक्षम होने पर on_commit() कॉल on_commit() और आप एक परमाणु ब्लॉक के भीतर नहीं हैं, परिणामस्वरूप त्रुटि होगी।

परीक्षणों में उपयोग करें

Django के TestCase क्लास ने प्रत्येक परीक्षण को एक लेनदेन में लपेटता है और प्रत्येक परीक्षण के बाद उस लेनदेन को वापस ले लेता है, ताकि परीक्षण अलगाव प्रदान किया जा सके। इसका मतलब है कि कोई भी लेन-देन वास्तव में प्रतिबद्ध नहीं है, इस प्रकार आपके on_commit() कॉलबैक कभी भी नहीं चलेंगे। यदि आपको on_commit() कॉलबैक के परिणामों का परीक्षण करने की आवश्यकता है, तो इसके बजाय TransactionTestCase उपयोग करें।

कोई रोलबैक हुक क्यों नहीं?

एक रोलबैक हुक कमिट हुक की तुलना में मजबूती से लागू करने के लिए कठिन है, क्योंकि विभिन्न प्रकार की चीजें एक अंतर्निहित रोलबैक का कारण बन सकती हैं।

उदाहरण के लिए, यदि आपका डेटाबेस कनेक्शन हटा दिया गया है क्योंकि आपकी प्रक्रिया को बिना ग्रेसफुली बंद किए बिना मार दिया गया है, तो आपका रोलबैक हुक कभी नहीं चलेगा।

समाधान सरल है: परमाणु ब्लॉक (लेन-देन) के दौरान कुछ करने के बजाय और फिर लेनदेन के विफल होने पर इसे पूर्ववत करने के बाद, on_commit() का उपयोग करें जब तक कि लेनदेन सफल होने के बाद इसे पहली जगह में करने में देरी न हो। यह बहुत आसान है जो आपने पहले कभी नहीं किया है!

निम्न स्तर के एपीआई

चेतावनी

यदि संभव हो तो हमेशा atomic() प्राथमिकता दें। यह प्रत्येक डेटाबेस की idiosyncrasies के लिए जिम्मेदार है और अवैध संचालन को रोकता है।

यदि आप अपने स्वयं के लेन-देन प्रबंधन को लागू कर रहे हैं तो निम्न स्तर के एपीआई केवल उपयोगी हैं।

Autocommit

Django प्रत्येक डेटाबेस कनेक्शन की स्वतः स्थिति को प्रबंधित करने के लिए django.db.transaction मॉड्यूल में एक सीधा एपीआई प्रदान करता है।

get_autocommit(using=None) [source]
set_autocommit(autocommit, using=None) [source]

ये फ़ंक्शन एक तर्क using हैं जो एक डेटाबेस का नाम होना चाहिए। यदि यह प्रदान नहीं किया गया है, तो Django "default" डेटाबेस का उपयोग करता है।

ऑटोकॉमिट शुरू में चालू होता है। यदि आप इसे बंद कर देते हैं, तो इसे बहाल करना आपकी जिम्मेदारी है।

एक बार जब आप स्वतः बंद कर देते हैं, तो आपको अपने डेटाबेस एडॉप्टर का डिफ़ॉल्ट व्यवहार मिलता है, और Django आपकी मदद नहीं करेगा। हालांकि पीईपी 249 में यह व्यवहार निर्दिष्ट है, एडेप्टर का कार्यान्वयन हमेशा एक दूसरे के अनुरूप नहीं होता है। उस एडेप्टर के प्रलेखन की समीक्षा करें जिसे आप सावधानीपूर्वक उपयोग कर रहे हैं।

आपको यह सुनिश्चित करना होगा कि कोई भी लेनदेन सक्रिय नहीं है, आमतौर पर ऑटोकॉमिट को वापस चालू करने से पहले एक commit() या rollback() जारी करके।

जब एक atomic() ब्लॉक सक्रिय होता है, तो Django ऑटोकॉमिट को बंद करने से इंकार कर देगा, क्योंकि यह परमाणुता को तोड़ देगा।

लेन-देन

लेन-देन डेटाबेस प्रश्नों का एक परमाणु समूह है। यहां तक ​​कि अगर आपका प्रोग्राम क्रैश हो जाता है, तो डेटाबेस गारंटी देता है कि या तो सभी परिवर्तन लागू होंगे, या उनमें से कोई भी नहीं।

Django लेनदेन शुरू करने के लिए एक एपीआई प्रदान नहीं करता है। लेन-देन शुरू करने का अपेक्षित तरीका set_autocommit() साथ set_autocommit() को अक्षम करना है।

एक बार जब आप किसी लेन-देन में होते हैं, तो आप या तो उन बदलावों को लागू करने के लिए चुन सकते हैं जो इस बिंदु पर commit() साथ लागू होते हैं, या उन्हें rollback() साथ रद्द करने के लिए। ये फ़ंक्शन django.db.transaction में परिभाषित किए django.db.transaction

commit(using=None) [source]
rollback(using=None) [source]

ये फ़ंक्शन एक तर्क using हैं जो एक डेटाबेस का नाम होना चाहिए। यदि यह प्रदान नहीं किया गया है, तो Django "default" डेटाबेस का उपयोग करता है।

जब एक atomic() ब्लॉक सक्रिय होता है, तो Django प्रतिबद्ध या रोलबैक करने से इंकार कर देगा, क्योंकि यह परमाणुता को तोड़ देगा।

Savepoints

एक सेवपॉइंट एक लेनदेन के भीतर एक मार्कर है जो आपको पूर्ण लेनदेन के बजाय एक लेनदेन का एक हिस्सा वापस करने में सक्षम बनाता है। Savepoint SQLite, PostgreSQL, Oracle, और MySQL (जब InnoDB स्टोरेज इंजन का उपयोग करके) बैकएंड के साथ उपलब्ध हैं। अन्य बैकएंड सेवपॉइंट फ़ंक्शन प्रदान करते हैं, लेकिन वे खाली संचालन हैं - वे वास्तव में कुछ भी नहीं करते हैं।

यदि आप ऑटोकॉमिट का उपयोग कर रहे हैं, तो Django के डिफ़ॉल्ट व्यवहार को सहेजना विशेष रूप से उपयोगी नहीं है। हालाँकि, एक बार जब आप atomic() साथ लेन-देन खोलते हैं, तो आप एक प्रतिबद्ध या रोलबैक के लिए डेटाबेस संचालन की एक श्रृंखला का निर्माण करते हैं। यदि आप एक रोलबैक जारी करते हैं, तो पूरा लेन-देन वापस ले लिया जाता है। Savepoint, पूर्ण रोलबैक के बजाय एक ठीक-ठीक रोलबैक प्रदर्शन करने की क्षमता प्रदान करती है, जो transaction.rollback() द्वारा किया जाएगा। क्रॉलबैक transaction.rollback()

जब atomic() डेकोरेटर को नेस्ट किया जाता है, तो यह आंशिक कमिट या रोलबैक की अनुमति देने के लिए एक बचत बिंदु बनाता है। आपको नीचे वर्णित कार्यों के बजाय atomic() का उपयोग करने के लिए दृढ़ता से प्रोत्साहित किया जाता है, लेकिन वे अभी भी सार्वजनिक एपीआई का हिस्सा हैं, और उन्हें अपदस्थ करने की कोई योजना नहीं है।

इनमें से प्रत्येक फ़ंक्शन एक तर्क using है जो एक डेटाबेस का नाम होना चाहिए जिसके लिए व्यवहार लागू होता है। यदि कोई using तर्क प्रदान नहीं किया using है, तो "default" डेटाबेस का उपयोग किया जाता है।

Django.db.transaction में तीन कार्यों द्वारा सेवप्वाइंट्स को नियंत्रित किया django.db.transaction :

savepoint(using=None) [source]

एक नया सहेजता है। यह लेन-देन में एक बिंदु है जो "अच्छी" स्थिति में जाना जाता है। Savepoint ID ( sid ) देता है।

savepoint_commit(sid, using=None) [source]

रिलीफ sid । सेवपॉइंट बनाए जाने के बाद से किए गए परिवर्तन लेनदेन का हिस्सा बन गए।

savepoint_rollback(sid, using=None) [source]

रोल सहेजने के लिए लेन-देन वापस करता है।

ये कार्य कुछ भी नहीं करते हैं यदि savepoint समर्थित नहीं हैं या यदि डेटाबेस स्वतः पूर्ण मोड में है।

इसके अलावा, एक उपयोगिता समारोह है:

clean_savepoints(using=None) [source]

अद्वितीय सहेजने वाले आईडी बनाने के लिए उपयोग किए जाने वाले काउंटर को रीसेट करता है।

निम्न उदाहरण savepoints के उपयोग को दर्शाता है:

from django.db import transaction

# open a transaction
@transaction.atomic
def viewfunc(request):

    a.save()
    # transaction now contains a.save()

    sid = transaction.savepoint()

    b.save()
    # transaction now contains a.save() and b.save()

    if want_to_keep_b:
        transaction.savepoint_commit(sid)
        # open transaction still contains a.save() and b.save()
    else:
        transaction.savepoint_rollback(sid)
        # open transaction now contains only a.save()

आंशिक रोलबैक प्रदर्शन करके डेटाबेस त्रुटि से उबरने के लिए सेवपॉइंट का उपयोग किया जा सकता है। यदि आप एक atomic() ब्लॉक के अंदर ऐसा कर रहे हैं, तो पूरे ब्लॉक को अभी भी वापस ले लिया जाएगा, क्योंकि यह नहीं पता है कि आपने निचले स्तर पर स्थिति को संभाला है! इसे रोकने के लिए, आप निम्नलिखित कार्यों के साथ रोलबैक व्यवहार को नियंत्रित कर सकते हैं।

get_rollback(using=None) [source]
set_rollback(rollback, using=None) [source]

ट्रूबैक फ्लैग को True सेट करना अंतरतम परमाणु ब्लॉक से बाहर निकलते समय रोलबैक पर बल देता है। अपवाद को उठाए बिना रोलबैक को ट्रिगर करने के लिए यह उपयोगी हो सकता है।

इसे False सेट करना इस तरह के रोलबैक को रोकता है। ऐसा करने से पहले, सुनिश्चित करें कि आपने वर्तमान परमाणु ब्लॉक के भीतर एक ज्ञात-अच्छे बचत के लिए लेन-देन वापस कर दिया है! अन्यथा आप परमाणुता को तोड़ रहे हैं और डेटा भ्रष्टाचार हो सकता है।

डेटाबेस-विशिष्ट नोट्स

SQLite में Savepoints

जबकि SQLite, बचत का समर्थन करता है, sqlite3 मॉड्यूल के डिजाइन में एक दोष उन्हें शायद ही उपयोग करने योग्य बनाता है।

जब स्वतः पूर्ण सक्षम किया जाता है, तो savepoints का कोई मतलब नहीं है। जब यह अक्षम हो जाता है, तो sqlite3 सहेजने के बयानों से पहले स्पष्ट रूप से करता है। (वास्तव में, यह SELECT , INSERT , UPDATE , DELETE और REPLACE अलावा किसी भी कथन से पहले करता है।) इस बग के दो परिणाम हैं:

  • सेवपॉइंट के लिए निम्न स्तर के एपीआई केवल एक लेनदेन के अंदर प्रयोग करने योग्य होते हैं। एक atomic() ब्लॉक के अंदर।
  • ऑटोकॉमिट बंद होने पर atomic() का उपयोग करना असंभव है।

MySQL में लेनदेन

यदि आप MySQL का उपयोग कर रहे हैं, तो आपकी टेबल लेनदेन का समर्थन कर सकती हैं या नहीं; यह आपके MySQL संस्करण और आपके द्वारा उपयोग किए जा रहे टेबल प्रकारों पर निर्भर करता है। ("तालिका प्रकार," से हमारा तात्पर्य "InnoDB" या "MyISAM" की तरह है।) MySQL लेनदेन की विशिष्टताएँ इस लेख के दायरे से बाहर हैं, लेकिन MySQL साइट पर MySQL लेनदेन की जानकारी है

यदि आपका MySQL सेटअप लेन-देन का समर्थन नहीं करता है, तो Django हमेशा ऑटोकॉमिट मोड में कार्य करेगा: जैसे ही वे कॉल किए जाएंगे, स्टेटमेंट निष्पादित और प्रतिबद्ध होंगे। यदि आपका MySQL सेटअप लेनदेन का समर्थन करता है , तो Django इस दस्तावेज़ में बताए अनुसार लेनदेन को संभाल लेगा।

PostgreSQL लेनदेन के भीतर अपवादों को संभालना

ध्यान दें

यह अनुभाग केवल तभी प्रासंगिक है जब आप अपने लेन-देन प्रबंधन को लागू कर रहे हों। यह समस्या Django के डिफ़ॉल्ट मोड में नहीं हो सकती है और atomic() इसे स्वचालित रूप से संभालती है।

एक लेनदेन के अंदर, जब पोस्टग्रेसीक्यूसी कर्सर पर कॉल एक अपवाद (आमतौर पर IntegrityError ) उठाता है, उसी लेनदेन में बाद के सभी SQL त्रुटि के साथ विफल हो जाएंगे "वर्तमान लेनदेन को निरस्त कर दिया जाता है, लेनदेन ब्लॉक के अंत तक प्रश्नों को अनदेखा किया जाता है"। हालांकि पोस्टग्रेसीक्यू में एक अपवाद को save() के save() सरल उपयोग की संभावना नहीं है, लेकिन अधिक उन्नत उपयोग पैटर्न हैं, जैसे कि अद्वितीय फ़ील्ड्स के साथ ऑब्जेक्ट्स को सहेजना, फोर्स_इन्टर / फोर्स_पडेट फ्लैग का उपयोग करके बचत करना या कस्टम एसक्यूएल को लागू करना।

इस तरह की त्रुटि से उबरने के कई तरीके हैं।

लेन-देन रोलबैक

पहला विकल्प पूरे लेन-देन को वापस करना है। उदाहरण के लिए:

a.save() # Succeeds, but may be undone by transaction rollback
try:
    b.save() # Could throw exception
except IntegrityError:
    transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone

कॉलिंग transaction.rollback() देन। क्रॉलबैक transaction.rollback() संपूर्ण लेन-देन को वापस करता है। किसी भी uncommitted डेटाबेस कार्रवाई खो जाएगा। इस उदाहरण में, a.save() द्वारा किए गए परिवर्तन नष्ट हो जाएंगे, भले ही उस ऑपरेशन में कोई त्रुटि न हो।

सेवपॉइंट रोलबैक

आप रोलबैक की सीमा को नियंत्रित करने के लिए savepoints का उपयोग कर सकते हैं। डेटाबेस ऑपरेशन करने से पहले जो विफल हो सकता है, आप सेवपॉइंट को सेट या अपडेट कर सकते हैं; इस तरह, यदि ऑपरेशन विफल हो जाता है, तो आप पूरे लेनदेन के बजाय एकल ऑफ़ेंडिंग ऑपरेशन को वापस कर सकते हैं। उदाहरण के लिए:

a.save() # Succeeds, and never undone by savepoint rollback
sid = transaction.savepoint()
try:
    b.save() # Could throw exception
    transaction.savepoint_commit(sid)
except IntegrityError:
    transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone

इस उदाहरण में, a.save() उस मामले में पूर्ववत नहीं होगा जहां b.save() एक अपवाद उठाता है।