2016-09-27 4 views
15

docs of atomic()Django में @atomic() का घोंसला संस्करण नहीं है?

परमाणु ब्लॉक से

एक महान सुविधा की तरह इस ध्वनि नेस्ट किया जा सकता है, लेकिन मेरे उपयोग के मामले में मैं विपरीत हैं: मैं लेन-देन ही के रूप में टिकाऊ होना चाहता हूँ @atomic() के साथ सजाए गए ब्लॉक को सफलतापूर्वक छोड़ दिया गया है।

क्या डीजेंगो के लेन-देन से निपटने में स्थायित्व सुनिश्चित करने का कोई तरीका है?

पृष्ठभूमि

लेनदेन ACID हैं। "डी" स्थायित्व के लिए खड़ा है। यही कारण है कि मुझे लगता है कि लेनदेन "डी" खोए बिना लेनदेन को घोंसला नहीं किया जा सकता है।

उदाहरण: यदि आंतरिक लेनदेन सफल होता है, लेकिन बाहरी लेनदेन नहीं होता है, तो बाहरी और आंतरिक लेनदेन वापस लुढ़क जाता है। नतीजा: आंतरिक लेनदेन टिकाऊ नहीं था।

मैं पोस्टग्रेएसक्यूएल का उपयोग करता हूं, लेकिन AFAIK इससे कोई फर्क नहीं पड़ता।

उत्तर

7

आप किसी भी एपीआई के माध्यम से ऐसा नहीं कर सकते हैं।

सभी एसीआईडी ​​गुणों को बनाए रखते हुए लेनदेन को घोंसला नहीं किया जा सकता है, और सभी डेटाबेस नेस्टेड लेनदेन का समर्थन नहीं करते हैं।

केवल बाहरी परमाणु ब्लॉक एक लेनदेन बनाता है। आंतरिक परमाणु ब्लॉक लेनदेन के अंदर एक savepoint बनाते हैं, और आंतरिक ब्लॉक से बाहर निकलने पर savepoint को वापस या रोल रोल। इस प्रकार, आंतरिक परमाणु ब्लॉक परमाणुता प्रदान करते हैं, लेकिन जैसा कि आपने नोट किया है, उदाहरण के लिए नहीं स्थायित्व।

बाहरीतम परमाणु ब्लॉक एक लेनदेन बनाता है, इसलिए परमाणुता प्रदान करना चाहिए, और यदि आप लेनदेन नहीं कर रहे हैं तो आप डेटाबेस में नेस्टेड परमाणु ब्लॉक नहीं कर सकते हैं।

यह सुनिश्चित करने का एकमात्र तरीका है कि आंतरिक ब्लॉक प्रतिबद्ध है, यह सुनिश्चित करना है कि लेनदेन में कोड किसी भी त्रुटि के बिना निष्पादित हो जाता है।

+0

मुझे आपके पाठ में मेरे प्रश्न का उत्तर नहीं मिला। आप कहते हैं कि मुझे यह सुनिश्चित करने की ज़रूरत है कि बाहरी परमाणु ब्लॉक प्रतिबद्ध हो। हाँ यह सच है। Django में यह कैसे करें? – guettli

+0

@guettli मैंने अपना जवाब अपडेट किया। ऐसा करने के लिए कोई एपीआई नहीं है, इसे प्राप्त करने का एकमात्र तरीका यह सुनिश्चित करना है कि लेनदेन में कोड किसी भी त्रुटि के बिना खत्म हो जाए। – knbk

+0

@guettli, यदि आप django में निम्न स्तर के लेनदेन प्रबंधन करना चाहते हैं, तो आप सीधे 'लेनदेन' पैकेज का उपयोग कर सकते हैं। उदाहरण के लिए, आप https://github.com/2ps/djenga/blob/master/djenga/db/nested_transactions.py देख सकते हैं, जो कुछ मैंने लिखा था जब django mysql में नेस्टेड लेनदेन का समर्थन नहीं करता था। – 2ps

6

मैं knbk के उत्तर से सहमत हूं कि यह संभव नहीं है: स्थायित्व केवल लेनदेन के स्तर पर मौजूद है, और परमाणु प्रदान करता है। यह इसे बचाने के स्तर के स्तर पर प्रदान नहीं करता है। उपयोग के मामले के आधार पर, कामकाज हो सकता है।

@atomic # possibly implicit if ATOMIC_REQUESTS is enabled 
def my_view(): 
    run_some_code() # It's fine if this gets rolled back. 
    charge_a_credit_card() # It's not OK if this gets rolled back. 
    run_some_more_code() # This shouldn't roll back the credit card. 

मुझे लगता है कि आप की तरह कुछ चाहते हैं:

@transaction.non_atomic_requests 
def my_view(): 
    with atomic(): 
     run_some_code() 
    with atomic(): 
     charge_a_credit_card() 
    with atomic(): 
     run_some_more_code() 

आपके उपयोग के मामले क्रेडिट कार्ड विशेष रूप से के लिए है (मेरा रूप

मैं आपके उपयोग के मामले में अनुमान लगाने कर रहा हूँ कुछ की तरह है जब मुझे कुछ साल पहले यह मुद्दा था), मेरे सहकर्मी ने पाया कि credit card processors actually provide mechanisms for handling this। ऐसा ही एक तंत्र, आपके उपयोग के मामले के लिए काम कर सकते हैं समस्या संरचना के आधार पर:

@atomic 
def my_view(): 
    run_some_code() 
    result = charge_a_credit_card(capture=False) 
    if result.successful: 
     transaction.on_commit(lambda: result.capture()) 
    run_some_more_code() 

एक अन्य विकल्प, रिकॉर्डिंग क्या आप में रुचि रखते हैं, एक लॉग डेटाबेस की तरह के लिए एक गैर-लेनदेन हठ तंत्र का उपयोग किया जाएगा या रिकॉर्ड करने के लिए चीजों की एक redis कतार।

+1

"क्रेडिट कार्ड प्रोसेसर का आपका लिंक वास्तव में इसे संभालने के लिए तंत्र प्रदान करता है" दो चरण प्रतिबद्ध प्रोटोकॉल की तरह दिखता है: https://en.wikipedia.org/wiki/Two-phase_commit_protocol – guettli

6

इस प्रकार के स्थायित्वएक कनेक्शन के साथ ACID के कारण असंभव है। (यानी कि एक घोंसला वाला ब्लॉक तब भी रहता है जब बाहरी ब्लॉक वापस घुमाया जाता है) यह एसीआईडी ​​का परिणाम है, न कि Django की समस्या। एक सुपर डेटाबेस की कल्पना करें और स्थिति B तालिका A तालिका के लिए एक विदेशी कुंजी है।

CREATE TABLE A (id serial primary key); 
CREATE TABLE B (id serial primary key, b_id integer references A (id)); 
-- transaction 
    INSERT INTO A DEFAULT VALUES RETURNING id AS new_a_id 
    -- like it would be possible to create an inner transaction 
     INSERT INTO B (a_id) VALUES (new_a_id) 
    -- commit 
-- rollback (= integrity problem) 

तो भीतरी "लेन-देन" टिकाऊ होना चाहिए, जबकि (बाह्य) लेन-देन वापस लुढ़का हो तो अखंडता टूट किया जाएगा। रोलबैक ऑपरेशन हमेशा लागू किया जाना चाहिए ताकि यह कभी विफल न हो, इसलिए कोई डेटाबेस घोंसला वाले स्वतंत्र लेनदेन को लागू नहीं करेगा। यह कारणता के सिद्धांत के खिलाफ होगा और इस तरह के चुनिंदा रोलबैक के बाद अखंडता की गारंटी नहीं दी जा सकती है। यह परमाणु के खिलाफ भी है।

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

Django एकाधिक डेटाबेस का समर्थन करता है, इसलिए एकाधिक कनेक्शन।

# no ATOMIC_REQUESTS should be set for "other_db" in DATABASES 

@transaction.atomic # atomic for the database "default" 
def my_view(): 
    with atomic(): # or set atomic() here, for the database "default" 
     some_code() 
     with atomic("other_db"): 
      row = OtherModel.objects.using("other_db").create(**kwargs) 
     raise DatabaseError 

"other_db" में डेटा प्रतिबद्ध रहता है।

Django में संभवतः एक ही डेटाबेस के लिए दो कनेक्शन के साथ एक चाल बनाने के लिए संभव है जैसे कि कुछ डेटाबेस बैकएंड के साथ दो डेटाबेस होंगे, लेकिन मुझे यकीन है कि यह अनचाहे है, यह गलतियों से ग्रस्त होगा, माइग्रेशन के साथ समस्याओं के साथ, डेटाबेस बैकएंड द्वारा बड़ा भार जो हर अनुरोध पर वास्तविक समांतर लेनदेन बनाना चाहिए और इसे अनुकूलित नहीं किया जा सकता है। दो वास्तविक डेटाबेस का उपयोग करना या कोड को पुनर्गठित करना बेहतर है।

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

संबंधित मुद्दे