2012-09-27 14 views
5

मैं वर्तमान में लेन-देन के साथ खेल रहा हूं और निम्नलिखित परिदृश्य के चारों ओर अपने दिमाग को लपेट नहीं सकता:यह लेनदेन ActiveRecord में क्यों काम नहीं करता है?

उपयोगकर्ता नाम "जॉनी" और पूर्ण नाम "जॉन स्मिथ" के साथ उपयोगकर्ता है।

मैं दो पटरियों को शान्ति शुरू करने और इस क्रम में निम्न कमांड निष्पादित करें:

कंसोल एक:

ActiveRecord::Base.transaction { user = User.find_by_username("foo"); sleep 10; user.update_attribute(:full_name, "#{user.full_name}-1"); } 

कंसोल बी:

ActiveRecord::Base.transaction { user = User.find_by_username("foo"); sleep 10; user.update_attribute(:full_name, "#{user.full_name}-2"); } 

तो समय निम्नलिखित है:

ए "जॉन स्मिथ"

पढ़ता है

बी पढ़ता है "जॉन स्मिथ"

एक लिखते हैं, "जॉन स्मिथ -1"

बी लिखते हैं, "जॉन स्मिथ -2"

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

कोई विचार क्यों होता है या अपेक्षित व्यवहार कैसे प्राप्त करें?

तरह का संबंध

निल्स

+0

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

+0

आपको क्या लगता है कि यह activerecord विशिष्ट है?यदि आप डेटाबेस कमांड लाइन इंटरफ़ेस से एक समान कार्य करते हैं तो परिणाम अलग होता है? –

+0

@FrederickCheung आपके द्वारा उपयोग किए जाने वाले एसक्यूएल पर निर्भर करता है। अगर यह 'अद्यतन ... अद्यतन के लिए' था तो यह अलग होगा। अभी भी ओपी उम्मीद नहीं करता है। लेकिन फिर यह निराशावादी लॉकिंग होगा: http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html –

उत्तर

4

जहां तक ​​मैं समझता हूँ कि लेन-देन लॉक करने के बारे में नहीं है, लेन-देन का मुख्य उद्देश्य परमाणु परिवर्तन सुनिश्चित करना है। उदाहरण के लिए जब आप अपने चेकिंग खाते से धन घटाते हैं और उन्हें अपने बचत खाते में जमा करते हैं तो आपको यह सुनिश्चित करने की ज़रूरत है कि दोनों आईएनएसईआरटी सफल हो गए हों या दोनों विफल हो गए या आपको असंगत स्थिति के साथ छोड़ दिया जाएगा। आपको जो चाहिए वह लॉकिंग है, उदा। http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html

अद्यतन: एसीआईडी ​​रोलबैक लेनदेन के लिए नहीं है जैसा कि मैं समझता हूं। यदि कोई त्रुटि नहीं है तो दोनों लेनदेन सफल होंगे। परिणामस्वरूप आपको क्या मिलता है अलगाव पर निर्भर करता है। यदि SERIALIZABLE स्तर का उपयोग किया गया था, तो आपको "जॉन स्मिथ-1-2" मिलेगा, लेकिन डिफ़ॉल्ट रूप से InnoDB REPEATABLE READ स्तर http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read का उपयोग कर रहा है, जिसका अर्थ है कि यदि SELECT गैर-लॉकिंग (User.find_by...) है तो यह पढ़ने के लिए रिकॉर्ड लॉक नहीं करेगा और आपको मिल जाएगा स्नैपशॉट से मूल परिणाम जो लेनदेन ए में शुरू किया गया था (बी 0 से SELECT बी लॉक नहीं होगा जब तक कि SERIALIZABLE के मामले में ए समाप्त नहीं हुआ)।

अद्यतन: इस बीच आप निराशावादी लॉकिंग के लिए http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html देख सकते हैं।

+0

सबसे पहले आपके उत्तर के लिए धन्यवाद। जहां तक ​​मुझे पता है कि MySQL के InnoDB- लेनदेन ACID (http://en.wikipedia.org/wiki/ACID) अनुपालन हैं। आपकी व्याख्या "मैं" को अनदेखा करती है, अलगाव का मतलब है समवर्ती लेनदेन का परिणाम वही है जैसा कि क्रमशः निष्पादित किया जाता है, जो वास्तव में यहां मामला नहीं है। तो सवाल यह है: ActiveRecord इस तरह क्यों काम नहीं करता है? – NilsHaldenwang

+0

आह, मैं स्पष्टीकरण के लिए thx देखता हूं। – NilsHaldenwang