2012-07-03 20 views
7

साथ अपेक्षा के अनुरूप काम नहीं कर रहा मैं एक रेल मॉडल में निम्नलिखित कोड है:डाटाबेस ताला रेल और Postgres

foo = Food.find(...) 
foo.with_lock do 
    if bar = foo.bars.find_by_stuff(stuff) 
    # do something with bar 
    else 
    bar = foo.bars.create! 
    # do something with bar 
    end 
end 

लक्ष्य यह सुनिश्चित करें कि प्रकार का एक बार बनाया जा रहा दो बार नहीं बनाया जा रहा है बनाने के लिए है।

कंसोल पर with_lock कार्यों का परीक्षण मेरी अपेक्षाओं की पुष्टि करता है। हालांकि, उत्पादन में, ऐसा लगता है कि या तो कुछ या सभी मामलों में लॉक अपेक्षित काम नहीं कर रहा है, और अनावश्यक बार का प्रयास किया जा रहा है - इसलिए, with_lock (हमेशा?) परिणामस्वरूप कोड की बारी के लिए इंतजार कर रहा है ।

यहां क्या हो सकता है?

अद्यतन सभी को खेद है कि "लॉकिंग फू आपकी मदद नहीं करेगा" !! मेरे उदाहरण में शुरुआत में बार लुकअप नहीं था। यह अब तय है।

+0

आप कहां से जांचते हैं कि एक बार पहले से मौजूद है या नहीं? –

+1

@FrederickCheung: आप जांच क्यों परेशान करेंगे? डेटाबेस के बाहर कोई भी जांच ** हमेशा ** छेद और दौड़ की स्थिति होगी। –

+0

मैं व्यक्तिगत रूप से नहीं करता लेकिन यह ओपी के लिए काम करने में सहायक हो सकता है कि उनकी समझ में से कौन सा समझ खराब हो। –

उत्तर

1

एक कारण यह है कि क्वेरी कैश में एक रेल ऐप में लॉक काम नहीं करेगा।

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

The issue has been reported गीथब पर।

2

आप एक अद्वितीय बाधा का उपयोग क्यों नहीं करते? यह विशिष्टता के लिए बनाया गया है

+0

मेरे पास एक असहज बाधा है, और यह उसका काम करता है। कभी-कभी समवर्ती बचत में से एक विफल रहता है। इसलिए, कोई अनावश्यक डेटा नहीं बनाया गया है, लेकिन कोड इसकी बारी के इंतजार के बजाय उड़ाता है। –

+0

आपको त्रुटि प्रबंधन के लिए टेबल लॉक की आवश्यकता नहीं है, यह आपके एप्लिकेशन को बहुत धीमा कर देता है। आरओआर में कुछ बेहतर होना चाहिए, लेकिन मैं आपकी मदद नहीं कर सकता। –

+3

@ जॉनबचिर: यह उड़ाता है क्योंकि आप अद्वितीय बाधा का उल्लंघन करते समय उठाए गए अपवाद को पकड़ और संभालने नहीं कर रहे हैं। आप ** ** उन अपवादों को जाल और संभाल लेंगे, वहां कुछ भी नहीं है जो आप उन्हें रोकने के लिए रेल में कर सकते हैं। इस तरह की चीजों के साथ एकमात्र सायन रणनीति डेटाबेस को इसके साथ सौदा करने देती है, आपके कोड को बस कोशिश करनी चाहिए और अपेक्षित अपवादों और असफलताओं से निपटना चाहिए। –

6

आप with_lock के बारे में उलझन में हैं। fine manual से:

with_lock (लॉक = true)

Wraps पारित कर दिया ब्लॉक के लेनदेन में, उपज से पहले वस्तु ताला लगा। आप SQL लॉकिंग क्लॉज को तर्क के रूप में पास कर सकते हैं (lock! देखें)।

यदि आप इसे क्या with_lock आंतरिक रूप से करता है, तो आप देखेंगे कि यह lock! चारों ओर एक पतली आवरण से थोड़ा अधिक है:

ताला (लॉक = true)

प्राप्त इस रिकॉर्ड पर एक पंक्ति लॉक। अनुरोधित लॉक प्राप्त करने के लिए रिकॉर्ड को दोबारा लोड करता है।

तो with_lock बस एक पंक्ति लॉक कर रहा है और foo की पंक्ति लॉक कर रहा है।

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

+0

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

+0

@ जॉनबचिर: आपको क्या लगता है कि 'foo.with_lock' करता है और आपको ऐसा क्यों लगता है कि इसे आपकी समस्या का समाधान करना चाहिए? –

+1

@muistooshort मैं इस बयान के साथ अधिक सहमत नहीं हो सकता, "इस लॉकिंग बकवास से परेशान न करें"। आपका सुझाव मेरे लिए पूरी तरह से काम करता है। धन्यवाद। – Hoa

1

इस स्थिति से निपटने का सही तरीका सही रेल डॉक्स में वास्तव में है:।

http://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by

begin 
    CreditAccount.find_or_create_by(user_id: user.id) 
rescue ActiveRecord::RecordNotUnique 
    retry 
end 

("find_or_create_by" नहीं परमाणु, इसके वास्तव में एक खोज और फिर एक बनाने है तो की जगह कि आपके खोज के साथ और फिर बनाएं। इस पृष्ठ पर दस्तावेज़ इस मामले का बिल्कुल वर्णन करते हैं।)

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