2012-01-27 8 views
5

मैं इस परिदृश्य है: आवेदन करने के लिए
"अद्यतन के लिए" v/s "शेयर मोड में लॉक": अनुमति दें समवर्ती धागे बंद कर दिया पंक्ति के अद्यतन "राज्य" मूल्य को पढ़ने के लिए

  • उपयोगकर्ता एक्स लॉग स्थान एलसी 1 से: इसे कॉल करें Ulc1
  • उपयोगकर्ता एक्स (हैक किया गया है, या उसके कुछ दोस्त को उनके लॉगिन प्रमाण पत्र को पता है, या वह सिर्फ अपनी मशीन पर एक अलग ब्राउज़र से लॉग इन करता है, आदि .. आपको बिंदु मिल गया है) स्थान lc2 से एक ही समय में लॉग इन करें: इसे पर कॉल करें Ulc2

मैं एक मुख्य सर्वलेट जो उपयोग कर रहा हूँ: सेट झूठी
को autocommit - - - डेटाबेस पूलिंग
से एक कनेक्शन हो जाता है
एक आदेश है कि एप्लिकेशन परतों के माध्यम से चला जाता है निष्पादित करता है: यदि सभी सफल, सेट एक सच करने के लिए autocommit " अंत में "बयान, और कनेक्शन बंद कर देता है। अन्यथा अगर कोई अपवाद होता है, रोलबैक()।

मेरे डेटाबेस में (mysql/innoDb) मेरे पास पंक्ति कॉलम के साथ "इतिहास" तालिका है:
आईडी (प्राथमिक कुंजी) | उपयोगकर्ता नाम | तिथि | विषय | लॉक

कॉलम "लॉक" डिफ़ॉल्ट मान "झूठा" है और यह एक ध्वज के रूप में कार्य करता है जो चिह्नित करता है कि कोई विशिष्ट पंक्ति लॉक है या नहीं।
प्रत्येक पंक्ति तो परिदृश्य में वापस (के रूप में यू उपयोगकर्ता नाम स्तंभ से देख सकते हैं)

एक उपयोगकर्ता के लिए विशिष्ट है:
-> Ulc1 तारीख के लिए डाटाबेस से अद्यतन करने के लिए अपने इतिहास आदेश भेजता है " डी "और विषय" टी "।

-> Ulc2 सटीक एक ही समय में एक ही तारीख 'डी' के लिए डाटाबेस और ही विषय "टी" से ही आदेश को अद्यतन इतिहास भेजता है।

मैं एक mysql/InnoDB लॉकिंग सिस्टम है कि सक्षम हो जाएगा लागू करना चाहते हैं, जो भी धागा निम्नलिखित की जांच करने के लिए आ रहा है:

स्तंभ इस पंक्ति के लिए "बंद" है सच है या नहीं? यह के रूप में बंद कर दिया झंडा और अद्यतन फिर बंद कर दिया रीसेट:

  • अगर सही है, उपयोगकर्ता के लिए संदेश लौट कि
  • अगर सच नहीं (यानी बंद नहीं) "वह पहले से ही किसी अन्य स्थान से एक ही डेटा अपडेट कर रहा है" झूठ एक बार खत्म हो गया।

इनमें से कौन सी दो mysql लॉकिंग तकनीक, वास्तव में दूसरे आने वाले धागे को लॉक कॉलम के "अद्यतन" मान को पढ़ने के लिए WT कार्रवाई करने का निर्णय लेने की अनुमति देगी?

क्या मुझे "अद्यतन के लिए" या "साझा मोड में लॉक" का उपयोग करना चाहिए?

इस परिदृश्य बताते हैं मैं क्या करना चाहते:
- Ulc1 धागा पहले आता है: स्तंभ "बंद" गलत है, सच के लिए सेट और अद्यतन करने की प्रक्रिया जारी रखने के लिए
- Ulc2 धागा आता है, जबकि Ulc1 के लेन-देन की प्रक्रिया में अब भी है और भले ही पंक्ति innoDb कार्यक्षमताओं के माध्यम से बंद हो, लेकिन इसे प्रतीक्षा करने की ज़रूरत नहीं है, लेकिन वास्तव में कॉलम लॉक किए गए "नए" मान को पढ़ता है जो "सत्य" है, और इसलिए वास्तव में तब तक इंतजार नहीं करना चाहिए जब तक कि Ulc1 लेनदेन नहीं हो जाता "लॉक" कॉलम के मान को पढ़ें (वैसे भी उस समय तक इस कॉलम का मान पहले से ही गलत पर रीसेट कर दिया जाएगा)।

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

इस परिदृश्य के लिए लॉकिंग तंत्र का उपयोग करने के बारे में कोई भी सिफारिश की सराहना की जाती है।
यदि पंक्ति को लॉक किया गया है तो "चेक" करने का एक बेहतर तरीका है (सत्य/झूठी कॉलम ध्वज का उपयोग करने के अलावा) कृपया मुझे इसके बारे में बताएं।
धन्यवाद

समाधान (आधारित JDBC स्यूडोकोड उदाहरण पर @ Darhazer के जवाब)

तालिका: [आईडी (प्राथमिक कुंजी) | username | तिथि | विषय | बंद कर दिया]

connection.setautocommit(false); 
//transaction-1 
PreparedStatement ps1 = "Select locked from tableName for update where id="key" and locked=false); 
ps1.executeQuery(); 

//transaction 2 
PreparedStatement ps2 = "Update tableName set locked=true where id="key"; 
ps2.executeUpdate(); 
connection.setautocommit(true);// here we allow other transactions threads to see the new value 

connection.setautocommit(false); 
//transaction 3 
PreparedStatement ps3 = "Update tableName set aField="Sthg" where id="key" And date="D" and topic="T"; 
ps3.executeUpdate(); 

// reset locked to false 
PreparedStatement ps4 = "Update tableName set locked=false where id="key"; 
ps4.executeUpdate(); 

//commit 
connection.setautocommit(true); 

उत्तर

5

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

आपके परिदृश्य में 1 लेनदेन होना सबसे अच्छा है जो रिकॉर्ड के लिए चयन के साथ रिकॉर्ड लॉक करता है, रिकॉर्ड पर काम करने के अलावा और प्रतिबद्ध/रोलबैक पर तीसरे रिकॉर्ड को अनलॉक करता है।

अद्यतन के लिए चयन के साथ दूसरा थ्रेड लेनदेन पहले पूरा होने की प्रतीक्षा करेगा, फिर वास्तविक मूल्य पढ़ेगा और अन्य लेनदेन के साथ जारी नहीं रहने का फैसला करेगा, लेकिन उपयोगकर्ता को सूचित करने के लिए कि रिकॉर्ड लॉक है।

डेडलॉक से बचने के लिए, सुनिश्चित करें कि आप एक अद्वितीय इंडेक्स का उपयोग कर select for update कर रहे हैं।

उदाहरण कोड: आपकी मदद के लिए

connection.setautocommit(false); 
//transaction-1 
PreparedStatement ps1 = "Select locked from tableName for update where id="key" and locked=false); 
ps1.executeQuery(); 

//transaction 2 
PreparedStatement ps2 = "Update tableName set locked=true where id="key"; 
ps2.executeUpdate(); 
connection.setautocommit(true); // here we allow other transactions/threads to see the new value 

connection.setautocommit(false); 
//transaction 3 
PreparedStatement ps3 = "Update tableName set aField="Sthg" where id="key" And date="D" and topic="T"; 
ps3.executeUpdate(); 

// probably more queries 

// reset locked to false 
PreparedStatement ps4 = "Update tableName set locked=false where id="key"; 
ps4.executeUpdate(); 

//commit 
connection.setautocommit(true); 
+0

THX। लेकिन मुझे वह हिस्सा नहीं मिला जहां आपने दूसरे धागे का उल्लेख किया था: आपका मतलब है कि दूसरा धागा थ्रेड 1 द्वारा रिकॉर्ड अनलॉक होने से पहले भी "लॉक" के अपडेट किए गए मान को कॉल करने में सक्षम होगा? – shadesco

+0

@shadesco विचार लॉक मान को लॉक नहीं करना है जब आप इसे पहले से ही सही मानते हैं, उदा। रिकॉर्ड बंद है। लॉक टाइम को डीबी में न्यूनतम रखें और एप्लिकेशन में कार्यान्वित करें (यदि आप पूरे लेनदेन के समय के लिए रिकॉर्ड लॉक करते हैं, तो 'लॉक' मान होने का कोई मतलब नहीं है)। आप रिकॉर्ड को भी लॉक कर सकते हैं, लेकिन लॉक कॉलम में परिवर्तन करने के बाद, अन्य लेन-देन नए मान को देखेंगे। –

+0

मुझे लगता है कि मेरा मतलब क्या है, लेकिन मैंने आपके लिए एक प्रश्न के साथ एक छोटा अपडेट हिस्सा लिखा है, क्या आप इसे देख सकते हैं? – shadesco

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