2012-07-05 10 views
6

उत्पन्न करने वाली संग्रहीत प्रक्रिया के साथ MySQL deadlocks मेरे पास एक "टिकट" तालिका से यूआईडी उत्पन्न करने वाली एक संग्रहीत प्रक्रिया है, लेकिन लोड के तहत मुझे बहुत सारे डेडलॉक्स मिल रहे हैं। जब भी मेरे कार्य को एक नया यूआईडी चाहिए तो मैं कई बार समवर्ती कनेक्शन से इस प्रक्रिया को बुला रहा हूं।यूआईडी

BEGIN 
    DECLARE a_uid BIGINT(20) UNSIGNED; 
    START TRANSACTION; 
    SELECT uid INTO a_uid FROM uid_data FOR UPDATE; # Lock 
    INSERT INTO uid_data (stub) VALUES ('a') ON DUPLICATE KEY UPDATE uid=uid+1; 
    SELECT a_uid+1 AS `uid`; 
    COMMIT; 
END 

मैं उपयोग करने पर विचार किया:

BEGIN 
    REPLACE INTO uid_data (stub) VALUES ('a'); 
    SELECT LAST_INSERT_ID(); 
END 

हालांकि मैं अगर है कि समवर्ती कनेक्शन के साथ सुरक्षित रूप में वहाँ कोई ताला है, SELECT FOR UPDATE के साथ पहली प्रक्रिया के विपरीत होगा यकीन नहीं था।

mysql> DESCRIBE uid_data; 
+-------+---------------------+------+-----+---------+----------------+ 
| Field | Type    | Null | Key | Default | Extra   | 
+-------+---------------------+------+-----+---------+----------------+ 
| uid | bigint(20) unsigned | NO | PRI | NULL | auto_increment | 
| stub | char(1)    | NO | UNI | NULL |    | 
+-------+---------------------+------+-----+---------+----------------+ 

मैं पढ़ने के लिए प्रतिबद्ध लेनदेन अलगाव के लिए सेट किया हुआ:

यहाँ तालिका है

mysql> SHOW VARIABLES LIKE 'tx_isolation'; 
+---------------+-----------------+ 
| Variable_name | Value   | 
+---------------+-----------------+ 
| tx_isolation | READ-COMMITTED | 
+---------------+-----------------+ 

यहाँ है कि मैं क्या से SHOW ENGINE INNODB STATUS;

... 
... dozens and dozens of the following record locks... 

Record lock, heap no 1046 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
0: len 1; hex 61; asc a;; 
1: len 8; hex 00000000000335f2; asc  5 ;; 

Record lock, heap no 1047 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
0: len 1; hex 61; asc a;; 
1: len 8; hex 00000000000335f1; asc  5 ;; 

*** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 13 page no 4 n bits 1120 index `stub` of table `my_db`.`uid_data` trx id 13AA89 lock_mode X waiting 
Record lock, heap no 583 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
0: len 1; hex 61; asc a;; 
1: len 8; hex 00000000000334a8; asc  4 ;; 

*** WE ROLL BACK TRANSACTION (1) 

मैं वापस हो रही है अगर कोई समझा सकता है कि क्या हो रहा है और उन्हें कैसे टाला जा सकता है, तो आभारी रहें।

+0

जानकारी के लिए: इस सरल अनुक्रम का उपयोग करते समय भी डेडलॉक होता है: 'ट्रांज़ेक्शन प्रारंभ करें; अद्यतन के लिए uid_data से यूआईडी चुनें; अद्यतन uid_data SET uid = uid +1 [[यहां संभव डेडलॉक]]; COMMIT; '(इसलिए इसका 'ऑन डिप्लिकेट' क्लॉज से कोई लेना देना नहीं है)। हालांकि, 'दोहराए गए पढ़ने' के अलगाव स्तर के साथ कोई डेडलॉक नहीं होता है। मुझे अभी भी पता नहीं है कि इस बिंदु से क्या निष्कर्ष निकालना है। – RandomSeed

उत्तर

0

एक गतिरोध इस परिदृश्य में होता है:

लेनदेन 1: एक ताला (SELECT...FOR UPDATE) अनुरोध करता है और प्राप्त कर लेता है यह

लेनदेन 2: एक ताला (SELECT...FOR UPDATE) अनुरोध करता है और इंतज़ार करना होगा

लेनदेन 1: डालने की कोशिश करता है, डुप्लिकेट हिट करता है, इसलिए अद्यतन (INSERT...ON DUPLICATE KEY UPDATE) => डेडलॉक

मुझे पुनः के बारे में भी निश्चित नहीं है Ason, मुझे संदेह है कि यह ON DUPLICATE KEY UPDATE के साथ कुछ करने के लिए है। मैं अभी भी जांच कर रहा हूं और अगर मुझे पता चल जाए तो वापस आ जाएगा।

BEGIN 
    START TRANSACTION; 
    SELECT uid FROM uid_data FOR UPDATE; 
    UPDATE uid_data SET uid = uid +1; -- here, a deadlock would be detected in a blocked, concurrent connection 
    COMMIT; 
END 

इस बारे में क्या:

[संपादित करें] एक गतिरोध भी साथ होता है

BEGIN 
    START TRANSACTION;  
    UPDATE uid_data SET uid = uid +1; 
    SELECT uid FROM uid_data; 
    COMMIT; 
END 

आपको अपने सभी stub colum छोड़ सकता है। एकमात्र कमी यह है कि आपको अपनी पंक्ति को एक पंक्ति के साथ अपना यूआईडी_डेटा शुरू करना होगा।

+0

क्या संशोधित संग्रहीत प्रक्रिया किसी भी प्रकार की लॉकिंग के साथ समेकन संभालती है? – Sencha

+0

@ सेन्चा हां, 'अद्यतन' परमाणु, और यह लेनदेन के अंत तक पंक्ति (ओं) को भी ताला लगा देता है। हालांकि, मैं अभी भी आपके मूल अनुक्रम में मृत ताला के कारण के बारे में बहुत उत्सुक हूं (अपने प्रश्न पर मेरी टिप्पणियां भी देखें)। – RandomSeed

0

आप इस सुरक्षित धागा है और मेज से लॉक नहीं करेगा अगर यह (अपडेट का वास्तविक बयान के दौरान छोड़कर) MyISAM है की तरह

CREATE TABLE `uid_data` (
    `uid` BIGINT(20) UNSIGNED NOT NULL 
) 
COLLATE='utf8_general_ci' 
ENGINE=MyISAM; 

एक मेज पर

UPDATE uid_data SET uid = LAST_INSERT_ID(uid+1); 
SELECT LAST_INSERT_ID(); 

उपयोग करने का प्रयास कर सकते हैं।

2

यह करें:

uid BIGINT(20) UNSIGNED NOT NULL PRIMARY KEY auto_increment 

को

BEGIN 
    INSERT INTO tickets VALUES (NULL); 
    SELECT LAST_INSERT_ID(); 
END 

uid धारावाहिक बराबर है आप इस दृष्टिकोण के साथ किसी भी गतिरोध का अनुभव नहीं करना चाहिए:

CREATE TABLE tickets 
(
    uid serial 
) 

फिर अगली uid पाने के लिए और आप जितना चाहें उतने कनेक्शन फेंक सकते हैं।

+0

मुझे स्पष्टता के लिए जोड़ना चाहिए, कि LAST_INSERT_ID() दायरा प्रतिबंधित है - उदा। यदि इनमें से 1000 प्रश्न एक साथ चल रहे हैं तो किसी भिन्न कनेक्शन के लिए गलत संख्या प्राप्त करने का कोई जोखिम कभी नहीं होता है। –

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