MySQL: लेन-देन बनाम लॉकिंग टेबल


110

मैं डेटाबेस अखंडता को सुनिश्चित करने के लिए लेनदेन बनाम लॉकिंग टेबल के साथ थोड़ा भ्रमित हूं और यह सुनिश्चित करता हूं कि एक चयन और अद्यतन सिंक में बना रहे और कोई अन्य कनेक्शन इसके साथ हस्तक्षेप न करे। मुझे निम्न की जरूरत है:

SELECT * FROM table WHERE (...) LIMIT 1

if (condition passes) {
   // Update row I got from the select 
   UPDATE table SET column = "value" WHERE (...)

   ... other logic (including INSERT some data) ...
}

मुझे यह सुनिश्चित करने की आवश्यकता है कि कोई अन्य प्रश्न हस्तक्षेप नहीं करेगा और उसी तरह से प्रदर्शन करेगा SELECT('पुराने मूल्य को पढ़ते हुए) इससे पहले कि कनेक्शन पंक्ति को अपडेट करना समाप्त कर दे।

मुझे पता है कि मैं LOCK TABLES tableसिर्फ यह सुनिश्चित करने के लिए डिफ़ॉल्ट हो सकता हूं कि एक समय में केवल 1 कनेक्शन ऐसा कर रहा है, और जब मैं काम कर रहा हूं, तो इसे अनलॉक कर सकता हूं, लेकिन ऐसा लगता है जैसे ओवरकिल। रैपिंग कि एक लेनदेन में एक ही काम करते हैं (कोई अन्य कनेक्शन एक ही प्रक्रिया का प्रयास करता है, जबकि एक और प्रसंस्करण अभी भी है) सुनिश्चित करता है? या फिर एक होगा SELECT ... FOR UPDATEया SELECT ... LOCK IN SHARE MODEबेहतर हो सकता है?

जवाबों:


173

लॉकिंग टेबल अन्य DB उपयोगकर्ताओं को आपके द्वारा लॉक की गई पंक्तियों / तालिकाओं को प्रभावित करने से रोकता है। लेकिन अपने आप में और आपके लॉकेट यह सुनिश्चित नहीं करेंगे कि आपका तर्क सुसंगत स्थिति में है।

एक बैंकिंग प्रणाली के बारे में सोचो। जब आप ऑनलाइन बिल का भुगतान करते हैं, तो लेनदेन से कम से कम दो खाते प्रभावित होते हैं: आपका खाता, जिसमें से पैसा लिया जाता है। और रिसीवर का खाता, जिसमें धन स्थानांतरित किया जाता है। और बैंक का खाता, जिसमें वे खुशी से लेन-देन पर लगाए गए सभी सेवा शुल्क जमा करेंगे। यह देखते हुए (जैसा कि हर कोई इन दिनों जानता है) कि बैंक असाधारण रूप से मूर्ख हैं, मान लें कि उनकी प्रणाली इस तरह काम करती है:

$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
    charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;

$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance

अब, बिना किसी ताले और लेन-देन के साथ, यह प्रणाली विभिन्न दौड़ की स्थिति के लिए असुरक्षित है, जिसमें से सबसे बड़ा भुगतान आपके खाते में किया जा रहा है या समानांतर में रिसीवर का खाता है। जबकि आपके कोड ने आपके शेष राशि को पुनः प्राप्त कर लिया है और विशाल_ओवरड्राफ्ट_फिसेस () और व्हाट्सएप कर रहा है, यह पूरी तरह से संभव है कि कुछ अन्य भुगतान समान प्रकार के कोड को समानांतर में चला रहे हों। वे आपका शेष राशि प्राप्त करेंगे (कहते हैं, $ 100), उनका लेनदेन करें (आपके द्वारा भुगतान किए जा रहे $ 20 को निकाल लें, और $ 30 वे आपके साथ खराब कर रहे हैं), और अब दोनों कोड पथ में दो अलग-अलग शेष राशि हैं: $ 80 और $ 70। इस पर निर्भर करता है कि लोग अंतिम स्थान पर हैं, आप अपने खाते में उन दो शेष राशि के साथ समाप्त हो जाएंगे, $ 50 के बजाय आपको ($ 100 - $ 20 - $ 30) समाप्त होना चाहिए। इस मामले में, "आपके पक्ष में बैंक त्रुटि"

अब, मान लीजिए कि आप ताले का उपयोग करते हैं। आपका बिल भुगतान ($ 20) पहले पाइप को हिट करता है, इसलिए यह आपके खाते के रिकॉर्ड को जीतता है और लॉक करता है। अब आपको अनन्य उपयोग मिल गया है, और शेष राशि से $ 20 घटा सकते हैं, और नए शेष राशि को शांति से लिख सकते हैं ... और आपका खाता $ 80 तक समाप्त हो जाएगा जैसा कि अपेक्षित है। लेकिन ... उह ... आप रिसीवर के खाते को अपडेट करने की कोशिश करते हैं, और यह बंद है, और कोड की तुलना में लंबे समय तक लॉक रहता है, आपके लेनदेन का समय समाप्त हो जाता है ... हम बेवकूफ बैंकों के साथ काम कर रहे हैं, इसलिए उचित त्रुटि होने के बजाय हैंडलिंग, कोड सिर्फ एक खींचता है exit(), और आपका $ 20 इलेक्ट्रॉनों के कश में गायब हो जाता है। अब आप $ 20 से बाहर हो गए हैं, और आपके पास अभी भी रिसीवर के लिए $ 20 बकाया है, और आपका टेलीफोन फिर से तैयार हो जाता है।

इसलिए ... लेनदेन दर्ज करें। आप एक लेन-देन शुरू करते हैं, आप अपने खाते को $ 20 डेबिट करते हैं, आप 20 डॉलर के साथ रिसीवर को क्रेडिट करने की कोशिश करते हैं ... और फिर से कुछ चल रहा है। लेकिन इस बार, इसके बजाय exit(), कोड बस कर सकता है rollback, और Poof, आपका $ 20 जादुई रूप से आपके खाते में वापस जोड़ दिया जाता है।

अंत में, यह इस पर उबलता है:

ताले किसी भी अन्य डेटाबेस रिकॉर्ड के साथ हस्तक्षेप करने से रोकते हैं जो आप के साथ काम कर रहे हैं। लेन-देन किसी "बाद में" त्रुटियों को आपके द्वारा किए गए "पहले" चीजों के साथ हस्तक्षेप करने से रोकते हैं। न तो अकेले गारंटी दे सकते हैं कि चीजें अंत में ठीक काम करती हैं। लेकिन एक साथ, वे करते हैं।

कल के पाठ में: द जॉय ऑफ डेडलॉक


4
मैं भी / अभी भी भ्रमित हूँ। कहते हैं कि शुरू करने के लिए रिसीवर के खाते में $ 100 था और हम अपने खाते से $ 20 बिल का भुगतान जोड़ रहे हैं। लेन-देन के बारे में मेरी समझ यह है कि जब वे शुरू करते हैं, तो कोई भी इन-ट्रांजैक्शन ऑपरेशन उस स्थिति में डेटाबेस को देखता है जो लेन-देन की शुरुआत में था। यानी: जब तक हम इसे नहीं बदलते, रिसीवर के खाते में $ 100 हैं। इसलिए ... जब हम $ 20 जोड़ते हैं तो हम वास्तव में $ 120 का संतुलन बनाते हैं। लेकिन क्या होगा अगर, हमारे लेनदेन के दौरान, किसी ने रिसीवर खाते को $ 0 में सूखा दिया? क्या इसे किसी तरह रोका गया है? क्या वे जादुई रूप से $ 120 फिर से प्राप्त करते हैं? क्या इसीलिए ताले की भी जरूरत है?
रस

हाँ, यह वह जगह है जहाँ ताले खेलने में आते हैं। एक उचित प्रणाली रिकॉर्ड को लॉक कर देगी, ताकि कोई अन्य रिकॉर्ड अपडेट न कर सके, जबकि लेनदेन प्रगति पर है। एक पैरानॉयड सिस्टम रिकॉर्ड पर बिना शर्त ताला लगा देगा ताकि कोई भी "बासी" संतुलन को न पढ़ सके।
मार्क बी

1
मूल रूप से अपने कोड पथ के अंदर चीजों को सुरक्षित करने के रूप में लेनदेन को देखें। "समानांतर" कोड पथों पर सुरक्षित चीज़ों को लॉक करता है। गतिरोध आने तक ...
मार्क बी

1
@ MarcB, तो हमें लेन-देन स्पष्ट रूप से क्यों करना होगा यदि अकेले लेनदेन का उपयोग करने से पहले से ही गारंटी है कि ताले जगह में हैं? क्या कोई ऐसा मामला भी होगा जिसके तहत हमें स्पष्ट रूप से लॉकिंग करना होगा क्योंकि अकेले लेनदेन अपर्याप्त हैं?
पचेरियर

2
यह उत्तर सही नहीं है और इससे गलत निष्कर्ष निकल सकते हैं। यह कथन: "ताले आपके साथ काम कर रहे किसी भी डेटाबेस रिकॉर्ड के साथ हस्तक्षेप करने से किसी और को रखते हैं। लेन-देन किसी भी" बाद में "त्रुटियों को आपके द्वारा किए गए" पहले "चीजों के साथ हस्तक्षेप करने से रोकते हैं। केवल अकेले ही यह गारंटी नहीं दे सकते हैं कि चीजें ठीक से काम करती हैं। अंत। लेकिन एक साथ, वे करते हैं। " - आपको निकाल दिया जाएगा, यह बहुत गलत और बेवकूफ़ है। देखें लेख: en.wikipedia.org/wiki/ACID , en.wikipedia.org/wiki/Isolation_(database_systems) और dev.mkql.com/doc/refman/5.1/ एन /…
निकोला Svitlica

14

आप लेन-देन के अंदर SELECT ... FOR UPDATEया चाहते हैं SELECT ... LOCK IN SHARE MODE, जैसा कि आपने कहा था, चूंकि सामान्य रूप से चयन होता है, भले ही वे लेनदेन में हों या नहीं, कोई तालिका लॉक नहीं होगी। आप जो चुनते हैं, वह इस बात पर निर्भर करेगा कि क्या आप चाहते हैं कि अन्य लेन-देन उस पंक्ति को पढ़ने में सक्षम हों जबकि आपका लेनदेन प्रगति पर है।

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

START TRANSACTION WITH CONSISTENT SNAPSHOTआपके लिए चाल नहीं चलेगा, क्योंकि अन्य लेनदेन अभी भी साथ आ सकते हैं और उस पंक्ति को संशोधित कर सकते हैं। यह नीचे दिए गए लिंक के शीर्ष पर उल्लिखित है।

यदि अन्य सत्र एक साथ एक ही तालिका को अपडेट करते हैं [...] आप उस स्थिति को देख सकते हैं जो डेटाबेस में कभी मौजूद नहीं थी।

http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html


7

लेनदेन की अवधारणाएं और ताले अलग-अलग हैं। हालांकि, लेनदेन ने एसीआईडी ​​सिद्धांतों का पालन करने में मदद करने के लिए ताले का इस्तेमाल किया। यदि आप पढ़ते / लिखते समय दूसरों को पढ़ने / लिखने से रोकने के लिए तालिका चाहते हैं, तो आपको ऐसा करने के लिए लॉक की आवश्यकता है। यदि आप डेटा अखंडता और निरंतरता सुनिश्चित करना चाहते हैं, तो आपके पास लेनदेन का बेहतर उपयोग था। मुझे लगता है कि ताले के साथ लेन-देन में अलगाव के स्तर की मिश्रित अवधारणाएं हैं। कृपया लेन-देन के अलगाव स्तर खोजें, SERIALIZE वह स्तर होना चाहिए जो आप चाहते हैं।


यह सही उत्तर होना चाहिए। लॉकिंग दौड़ की स्थिति को रोकने के लिए है, और लेनदेन निर्भर डेटा के साथ कई तालिकाओं को अपडेट करने के लिए है। दो पूरी तरह से अलग अवधारणाएं, इसके बावजूद कि लेनदेन ताले का उपयोग करते हैं।
ब्लू वाटर

6

जब मैं कोशिश कर रहा था तो एक समान समस्या थी IF NOT EXISTS ...और तब INSERTएक दौड़ की स्थिति का प्रदर्शन करना जब कई सूत्र एक ही तालिका को अपडेट कर रहे थे।

मुझे यहाँ समस्या का समाधान मिला: मानक SQL में INSERT IF NOT EXISTS क्वेरीज़ कैसे लिखनी है

मुझे लगता है कि यह सीधे आपके सवाल का जवाब नहीं देता है, लेकिन एक चेक के प्रदर्शन और एक ही बयान के रूप में सम्मिलित करने का एक ही सिद्धांत बहुत उपयोगी है; आपको अपना अद्यतन करने के लिए इसे संशोधित करने में सक्षम होना चाहिए।


2

आप लॉक और लेन-देन में भ्रमित हैं। वे आरएमडीबी में दो अलग-अलग चीजें हैं। लॉक समवर्ती संचालन को रोकता है जबकि लेनदेन डेटा अलगाव पर केंद्रित है। की जाँच करें इस स्पष्टीकरण और कुछ सुंदर समाधान के लिए महान लेख।


1
ताले दूसरों को आपके द्वारा काम कर रहे रिकॉर्ड के साथ हस्तक्षेप करने से रोकते हैं, यह वर्णन करता है कि यह क्या करता है, और लेनदेन बाद में होने वाली त्रुटियों (समानांतर में परिवर्तन करने वाले अन्य) को आपके द्वारा पहले की गई चीजों के साथ हस्तक्षेप करने से रोकते हैं (घटना में रोलबैक की अनुमति देता है) समानांतर में) लेन-देन पर बहुत अधिक रकम ... इन विषयों की उसकी समझ के बारे में क्या उलझन है?
स्टेविसमा

1

मैं एक का उपयोग करेंगे

START TRANSACTION WITH CONSISTENT SNAPSHOT;

के साथ शुरू करने के लिए, और एक

COMMIT;

के साथ समाप्त करने के लिए।

आपके बीच का कुछ भी आपके डेटाबेस के अन्य उपयोगकर्ताओं से अलग-थलग है यदि आपके भंडारण इंजन लेनदेन (जो InnoDB है) का समर्थन करता है, होता है।


1
जब तक वह जिस तालिका का चयन कर रहा है, उसे छोड़कर अन्य सत्रों के लिए लॉक नहीं किया जाएगा, जब तक कि वह विशेष रूप से इसे लॉक नहीं करता है (या जब तक उसका अद्यतन नहीं होता है), जिसका अर्थ है कि अन्य सत्र साथ आ सकते हैं और इसे SELECT और UPDATE के बीच संशोधित कर सकते हैं।
एलिसन आर।

MySQL डॉक्यूमेंटेशन में CONSISTENT SNAPSHOT वाले START TRANSACTION पर पढ़ने के बाद, मैं यह नहीं देखता कि यह वास्तव में एक ही पंक्ति को अपडेट करने से दूसरे कनेक्शन को कहां लॉक करता है। मेरी समझ यह है कि यह तब दिखाई देगा जब लेन-देन की शुरुआत में तालिका शुरू हुई थी। इसलिए यदि कोई अन्य लेन-देन प्रगति पर है, पहले ही एक पंक्ति प्राप्त कर चुका है और इसे अद्यतन करने वाला है, तो दूसरा लेन-देन अपडेट होने से पहले ही पंक्ति को देखेगा। यह संभावित रूप से उसी लेन-देन को अद्यतन करने का प्रयास कर सकता है जो अन्य लेन-देन करने वाला है। क्या यह सही है या मैं प्रगति में कुछ याद कर रहा हूं?
रयान

1
@ रेयान यह कोई लॉकिंग नहीं करता है; तुम सही हो। लॉकिंग (या नहीं) आपके द्वारा किए जाने वाले संचालन के प्रकार (SELECT / UPDATE / DELETE) से निर्धारित होती है।
एलिसन आर।

4
समझा। यह आपके स्वयं के लेन-देन को पढ़ने की निरंतरता देता है, लेकिन अन्य उपयोगकर्ताओं को आपके द्वारा किए जाने से पहले पंक्ति को संशोधित करने से रोकता नहीं है।
मार्टिन स्कैपेंडकोंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.