2012-04-21 21 views
5

प्रलेखन से find_or_create के लिए:डीबीआईएक्स :: कक्षा :: परिणामसेट की find_or_create विधि का उपयोग करते समय दौड़ की स्थिति से कैसे बचें?

नोट: क्योंकि find_or_create() डेटाबेस से पढ़ता है और उसके बाद संभवतः परिणाम के आधार पर आवेषण, इस विधि एक दौड़ इस शर्त के अधीन है। के बाद एक और प्रक्रिया तालिका में रिकॉर्ड बना सकती है, जो खोज पूरा हो गया है और निर्माण शुरू होने से पहले। इस समस्या को से बचने के लिए, एक लेनदेन के अंदर find_or_create() का उपयोग करें।

क्या पोस्टग्रेएसक्यूएल में किसी लेनदेन के अंदर find_or_create() का उपयोग करना पर्याप्त है?

उत्तर

6

नहीं है, प्रलेखन सही नहीं है। अकेले लेनदेन का उपयोग इस समस्या से बचें। यह केवल गारंटी देता है कि अगर कोई अपवाद होना चाहिए तो पूरा लेनदेन वापस लुढ़काया जाता है - ताकि डेटाबेस में कोई असंगत स्थिति जारी रहे।

से बचें इस समस्या से आपको तालिका को लॉक करना होगा - एक लेनदेन के अंदर, क्योंकि सभी ताले लेनदेन के अंत में जारी किए जाते हैं। कुछ ऐसा:

BEGIN; 
LOCK TABLE mytbl IN SHARE MODE; 

-- do your find_or_create here 

COMMIT; 

लेकिन यह सबकुछ के लिए जादू का इलाज नहीं है। यह एक प्रदर्शन समस्या बन सकती है, और वहाँ गतिरोध (समवर्ती लेनदेन पारस्परिक रूप से संसाधन है कि एक दूसरे को पहले से ही बंद कर दिया गया लॉक करने के लिए कोशिश कर रहा है) हो सकता है। PostgreSQL ऐसी स्थिति का पता लगाएगा और प्रतिस्पर्धी लेनदेन में से एक को रद्द कर देगा। विफलता पर ऑपरेशन को पुनः प्रयास करने के लिए आपको तैयार रहना चाहिए।

The PostgreSQL manual about locks.

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

+2

अन्य उपयोगी पृष्ठों की है। डॉक्स: http://www.postgresql.org/docs/current/interactive/mvcc.html PostgreSQL संस्करण 9.1 या बाद में क्रमिक कार्यान्वयन: http://wiki.postgresql.org/wiki/SSI अन्य अलगाव स्तर या PostgreSQL संस्करण: http : //www.postgresql.org/files/developer/concurrency.pdf – kgrittn

+0

लेकिन DBIC में "नकली चाबी उल्लंघन त्रुटि" को पकड़ने के लिए उचित तरीके क्या है? –

+0

@ यूगेनी: मुझे लगता है कि आप टिप्पणी के बजाए इसके लिए एक नया प्रश्न खोलें। आप स्वयं को कुछ टाइपिंग बचाने के लिए हमेशा इस से लिंक कर सकते हैं। –

0

find_or_create के इस कार्यान्वयन रेस स्थिति, ओपी में वर्णित रोकने चाहिए:

eval { 
    $row = $self->model->create({ ... }); 
} 
if([email protected] && [email protected] =~ /duplicate/i) { 
    $row = $self->model->find({ ... }); 
} 

यह भी सबसे अच्छा मामले में एक भी प्रश्न के find_or_create() कम कर देता है।

+1

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

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