MySQL: क्या कोई लेन-देन पंक्ति को लॉक करेगा?


13

मैंने पहले MySQL लेनदेन का उपयोग करने की कोशिश नहीं की है, मैं बस कुछ स्पष्ट करना चाहता हूं।

यदि दो उपयोगकर्ता बहुत सटीक समय पर किसी क्वेरी को निष्पादित करते हैं, तो MySQL इसको कैसे हैंडल करेगा? उदाहरण के लिए उपयोगकर्ता रिकॉर्ड को अपडेट करने का प्रयास कर रहे हैं।

user1: अपडेट टेबल सेट कॉलम = कॉलम - 4 जहां column_id = 1;

user2: अपडेट टेबल सेट कॉलम = कॉलम - 7 जहां column_id = 1;

अब अगर मैं लेन-देन का उपयोग करता हूं, तो क्या MySQL चुनेगा कि कौन सी क्वेरी पहले निष्पादित की जाएगी और पहली क्वेरी के प्रतिबद्ध होने तक दूसरे उपयोगकर्ता को लॉक करें? क्या वह टेबल लॉक या पंक्ति लॉक होगा?

क्या होगा यदि कोई तीसरा उपयोगकर्ता एक चयन वक्तव्य जारी करेगा? क्या होगा मान MySQL वापस आएगा?

PS यह इनोडब पर होगा।

जवाबों:


17

इस तरह का एक बयान MyISAM या InnoDB के साथ एक लेन-देन के साथ या autocommit = ON के साथ समान कार्य करता है। यह क्वेरी करने के लिए पर्याप्त ब्लॉक करता है, जिससे अन्य कनेक्शन अवरुद्ध हो जाता है। समाप्त होने पर, दूसरा कनेक्शन आगे बढ़ता है। सभी मामलों में, स्तंभ जल्द ही 11 से कम हो जाता है।

एक तीसरा उपयोगकर्ता 0 या 4 या 7 या 11. द्वारा घटाया गया मान देख सकता है, "बहुत सटीक समय" वास्तव में संभव नहीं है, क्योंकि प्रत्येक कथन के निष्पादन में कुछ बिंदु पर, एक एकल-थ्रेडेड लॉक की जाँच की जाती है / जो भी हो । यही कारण है कि वे, है जाएगा धारावाहिक जा, बस इतनी जल्दी है कि आप इसे नहीं देख सकता।

InnoDB केवल पंक्तियों को लॉक करता है, तालिकाओं को नहीं। (ठीक है, डीडीएल स्टेटमेंट बोल्डर लॉक करता है।)

क्या अधिक दिलचस्प हो जाता है एक लेनदेन जो दो चीजों को संशोधित करता है, या जो ध्यान देने योग्य समय लेता है:

इरादा मामला: एकल आइटम लेकिन समय लग रहा है:

BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;

इस प्रकार चयन की आवश्यकता है:

SELECT something  FOR UPDATE;

यह अन्य कनेक्शन को बताता है "मैं पंक्ति को अद्यतन करने का इरादा रखता हूं; कृपया मुझे गड़बड़ न करें"। (मैं इस उदाहरण को सामने लाता हूं, क्योंकि बहुत सारे न्यूबीज इस सूक्ष्मता को याद करते हैं।)

डेडलॉक मामला: 2 चीजों के साथ खिलवाड़:

BEGIN;    -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;

BEGIN;    -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;

यह एक गतिरोध का क्लासिक उदाहरण है - प्रत्येक चीज एक चीज को पकड़ती है और फिर दूसरी चीज के लिए पहुंचती है। स्पष्ट रूप से इसे काम करने के लिए नहीं बनाया जा सकता है। एक लेन-देन मारा जाता है; दूसरा पूरा हुआ। इसलिए, आपको त्रुटियों की जांच करनी चाहिए , ताकि आप इसे खोज सकें।

एक गतिरोध की सामान्य प्रतिक्रिया पूरे विफल लेनदेन को फिर से खेलना है। तब तक, दूसरा कनेक्शन हस्तक्षेप नहीं करेगा, और यह परेशानी के बिना आगे बढ़ना चाहिए। (ठीक है, फिर भी एक और कनेक्शन एक और गतिरोध पैदा कर सकता है।)

देरी का मामला: यदि दो कनेक्शन एक ही क्रम में कई चीजों को पकड़ते हैं , तो दूसरे को खत्म होने तक देरी हो सकती है। इसे "हमेशा के लिए इंतजार" से रखने के लिए, एक डिफ़ॉल्ट 50-सेकंड है innodb_lock_wait_timeout। आपकी जोड़ी सरल UPDATEsवास्तव में इस मामले का एक उदाहरण है। एक तो तुरंत खत्म हो जाएगा; पहले खत्म होने तक दूसरा रुका हुआ है।

ध्यान दें कि आपके द्वारा स्पर्श की जाने वाली चीजों को लगातार आदेश देकर एक डेडलॉक को (कुछ मामलों में) कैसे एक देरी में बदल दिया जा सकता है।

autocommit = 1: इस सेटिंग के साथ और बिना कॉल किए BEGIN, प्रत्येक कथन प्रभावी रूप से है:

BEGIN;
your statement
COMMIT;

autocommit = 0: यह होने की प्रतीक्षा में परेशानी है। जब आप एक लेखन क्वेरी करते हैं, तो एक BEGINसंक्षेप में उत्पन्न होता है। हालाँकि, अंततः जारी करना आपकी ज़िम्मेदारी है COMMIT। यदि आप ऐसा करने में विफल रहते हैं, तो आपको आश्चर्य होगा कि आपका सिस्टम क्यों लटका हुआ है। (एक और आम नौसिखिया बग।) मेरी सलाह: "कभी उपयोग न करें =0"।

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