मैं एक डेवलपर दृष्टिकोण से उत्तर प्रदान करूंगा।
मेरी राय में, जब आप एक पंक्ति विवाद का सामना करते हैं, जैसे कि आप जो वर्णन करते हैं, वह इसलिए है क्योंकि आपके आवेदन में एक बग है। ज्यादातर मामलों में इस प्रकार का विवाद एक खो-खो जोखिम का संकेत है। AskTom पर यह थ्रेड एक खोए हुए अद्यतन की अवधारणा को बताता है:
एक खोया अद्यतन तब होता है:
सत्र 1: टॉम के कर्मचारी रिकॉर्ड को पढ़ें
सत्र 2: टॉम का कर्मचारी रिकॉर्ड पढ़ें
सत्र 1: टॉम के कर्मचारी रिकॉर्ड को अपडेट करें
सत्र 2: टॉम के कर्मचारी रिकॉर्ड को अपडेट करें
सत्र 2 कभी भी बिना देखे ही सत्र 1 के परिवर्तन को छोड़ देगा - जिसके परिणामस्वरूप एक अद्यतन खो जाएगा।
आपने खोए हुए अद्यतन का एक बुरा पक्ष-प्रभाव अनुभव किया है: सत्र 2 को अवरुद्ध किया जा सकता है क्योंकि सत्र 1 अभी तक शुरू नहीं हुआ है। हालांकि मुख्य समस्या यह है कि सत्र 2 नेत्रहीन रिकॉर्ड को अपडेट करता है। मान लीजिए कि दोनों सत्र बयान जारी करते हैं:
UPDATE table SET col1=:col1, ..., coln=:coln WHERE id = :pk
दोनों बयानों के बाद, सत्र 1 के संशोधनों को अधिरोपित किया गया है, बिना सत्र 2 को सूचित किया गया है कि पंक्ति को सत्र 1 द्वारा संशोधित किया गया था।
खोया हुआ अपडेट (और विवाद पक्ष प्रभाव) कभी भी नहीं होना चाहिए, वे 100% परिहार्य हैं। आपको उन्हें दो मुख्य तरीकों से रोकने के लिए लॉकिंग का उपयोग करना चाहिए: आशावादी और निराशावादी लॉकिंग ।
1) निराशावादी लॉकिंग
आप एक पंक्ति को अद्यतन करना चाहते हैं। इस मोड में आप दूसरों को उस पंक्ति ( SELECT ... FOR UPDATE NOWAIT
स्टेटमेंट) पर लॉक का अनुरोध करके इस पंक्ति को संशोधित करने से रोकेंगे । यदि पंक्ति पहले से ही संशोधित हो रही है, तो आपको एक त्रुटि संदेश मिलेगा, जिसे आप अंतिम रूप से अंतिम-उपयोगकर्ता में अनुवाद कर सकते हैं (यह पंक्ति किसी अन्य उपयोगकर्ता द्वारा संशोधित की जा रही है)। यदि पंक्ति उपलब्ध है, तो अपने संशोधनों (अपडेट) करें, फिर जब भी आपका लेनदेन पूरा हो जाए, तब प्रतिबद्ध रहें।
2) आशावादी लॉकिंग
आप एक पंक्ति को अद्यतन करना चाहते हैं। हालाँकि, आप उस पंक्ति पर ताला नहीं रखना चाहते, शायद इसलिए कि आप पंक्ति (वेब-आधारित स्टेटलेस एप्लिकेशन) को अपडेट करने के लिए कई लेनदेन का उपयोग करते हैं, या शायद आप किसी भी उपयोगकर्ता को बहुत लंबे समय तक लॉक रखने से नहीं चाहते हैं ( जिसके परिणामस्वरूप अन्य लोग अवरुद्ध हो सकते हैं)। उस स्थिति में आप तुरंत लॉक का अनुरोध नहीं करेंगे। आप यह सुनिश्चित करने के लिए एक मार्कर का उपयोग करेंगे कि जब आपका अपडेट जारी किया जाएगा तो पंक्ति नहीं बदली गई है। आप सभी स्तंभों के मूल्य को कैश कर सकते हैं, या आप टाइमस्टैम्प कॉलम का उपयोग कर सकते हैं जो स्वचालित रूप से अपडेट हो जाता है, या अनुक्रम-आधारित कॉलम। जो भी आपकी पसंद, जब आप अपना अपडेट करने वाले हों, तो आप यह सुनिश्चित कर लेंगे कि उस पंक्ति पर मौजूद मार्कर क्वेरी जारी करके नहीं बदला है:
SELECT <...>
FROM table
WHERE id = :id
AND marker = :marker
FOR UPDATE NOWAIT
यदि क्वेरी पंक्ति में वापस आती है, तो अपना अपडेट करें। यदि ऐसा नहीं होता है, तो इसका मतलब यह है कि किसी ने पंक्ति को संशोधित किया है क्योंकि आपने इसे पिछली बार देखा था। आपको शुरुआत से ही प्रक्रिया को फिर से शुरू करना होगा।
नोट: यदि आपको अपने डीबी तक पहुंचने वाले सभी अनुप्रयोगों पर पूरा भरोसा है, तो आप आशावादी लॉकिंग के लिए सीधे अपडेट पर भरोसा कर सकते हैं। आप सीधे जारी कर सकते हैं:
UPDATE table
SET <...>,
marker = marker + 1
WHERE id = :id;
यदि कथन कोई पंक्ति अपडेट नहीं करता है, तो आप जानते हैं कि किसी ने इस पंक्ति को बदल दिया है और आपको सभी को शुरू करने की आवश्यकता है।
यदि सभी अनुप्रयोग इस योजना पर सहमत होते हैं, तो आप कभी किसी और द्वारा अवरुद्ध नहीं होंगे और आप अंधे अद्यतन से बचेंगे। हालाँकि, यदि आप पंक्ति को पहले से लॉक नहीं करते हैं, तो आप अभी भी अनिश्चित लॉकिंग के लिए अतिसंवेदनशील होते हैं यदि कोई अन्य एप्लिकेशन, बैच जॉब या सीधा अपडेट आशावादी लॉकिंग को लागू नहीं करता है। यही कारण है कि मैं हमेशा पंक्ति को लॉक करने की सलाह देता हूं, जो भी आपकी लॉकिंग स्कीम पसंद (प्रदर्शन हिट नगण्य हो सकती है क्योंकि आप पंक्ति को बंद करते समय पंक्ति सहित सभी मूल्यों को पुनः प्राप्त करते हैं)।
टी एल; डॉ
- पहले से ही लॉक होने के बिना एक पंक्ति को अपडेट करना संभावित "ठंड" के लिए आवेदन को उजागर करता है। इससे बचा जा सकता है अगर सभी डीएमएल डीबी आशावादी या निराशावादी लॉकिंग को लागू करते हैं।
- सत्यापित करें कि सेलेक्ट स्टेटमेंट रिटर्न वैल्यू किसी भी पिछले सिलेक्ट के अनुरूप है (किसी भी खोई हुई अपडेट समस्या से बचने के लिए)