आपको जो चाहिए वह है लॉक करना . लेन-देन वास्तव में "सख्ती से आवश्यक नहीं" हैं।
आप "निराशावादी लॉकिंग" और "आशावादी लॉकिंग" के बीच चयन कर सकते हैं। इन दो संभावनाओं में से किसके बारे में निर्णय आप पर निर्भर है और इसका मूल रूप से मूल्यांकन किया जाना चाहिए:
- आपके पास समसामयिकता का स्तर
- डेटाबेस पर होने वाली परमाणु संचालन की अवधि
- संपूर्ण ऑपरेशन की जटिलता
मैं शामिल चीजों का एक विचार बनाने के लिए इन दोनों को पढ़ने की सिफारिश करूंगा:
- आशावादी बनाम निराशावादी लॉकिंग
- MySQL में ऑप्टिमिस्टिक लॉकिंग (यहां कुछ उदाहरण दिखाते हैं कि कैसे लेन-देन की सख्त जरूरत नहीं है)
बेहतर समझाने के लिए एक उदाहरण
यह शायद इतना सुरुचिपूर्ण नहीं है, लेकिन केवल एक उदाहरण है जो दिखाता है कि बिना लेन-देन के (और यहां तक कि अद्वितीय बाधाओं के बिना भी) कैसे करना संभव है। निम्नलिखित संयुक्त INSERT + SELECT स्टेटमेट का उपयोग करने और इसके निष्पादन के बाद क्या करने की आवश्यकता है प्रभावित पंक्तियों की संख्या की जाँच करने के लिए। यदि प्रभावित पंक्तियों की संख्या 1 है तो यह अन्य तरीकों से सफल हुई है (यदि यह 0 है) तो एक टक्कर हुई है और दूसरी पार्टी जीत गई है।
INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT @startTime, @endTime, @uid, @group, @message, @deviceId
FROM `slot`
WHERE NOT EXISTS (
SELECT `id` FROM `slot`
WHERE `start` <= @endTime AND `end` >= @startTime
AND `devices_id` = @deviceId)
GROUP BY (1);
यह लेन-देन के बिना और एकल SQL ऑपरेशन के साथ प्राप्त आशावादी लॉकिंग का एक उदाहरण है।
जैसा लिखा है, यह समस्या है कि slot
में पहले से ही कम से कम एक पंक्ति होनी चाहिए तालिका को काम करने के लिए (अन्यथा SELECT क्लॉज हमेशा एक खाली रिकॉर्डसेट लौटाएगा और उस स्थिति में कोई टकराव नहीं होने पर कुछ भी नहीं डाला जाता है। इसे वास्तव में काम करने के लिए दो संभावनाएं हैं:
- तालिका में शायद अतीत की तारीख के साथ एक डमी पंक्ति डालें
-
फिर से लिखें ताकि मुख्य से खंड किसी भी तालिका को संदर्भित करता है जिसमें कम से कम एक पंक्ति हो या बेहतर एक छोटी तालिका बनाएं (शायद
dummy
नाम दिया गया हो) ) केवल एक कॉलम और उसमें केवल एक रिकॉर्ड के साथ और निम्नलिखित के रूप में फिर से लिखें (ध्यान दें कि GROUP BY क्लॉज की अब कोई आवश्यकता नहीं है)INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`) SELECT @startTime, @endTime, @uid, @group, @message, @deviceId FROM `dummy` WHERE NOT EXISTS ( SELECT `id` FROM `slot` WHERE `start` <= @endTime AND `end` >= @startTime AND `devices_id` = @deviceId);
यहां निर्देशों की एक श्रृंखला का पालन करते हुए कि यदि आप बस कॉपी/पेस्ट करते हैं तो विचार को कार्रवाई में दिखाया गया है। मैंने मान लिया है कि आप दिनांक और समय के अंकों के साथ एक संख्या के रूप में int फ़ील्ड पर दिनांक/समय को सांकेतिक शब्दों में बदलना करते हैं।
INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
VALUES (1008141200, 1008141210, 11, 2, 'Dummy Record', 14)
INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT 1408141206, 1408141210, 11, 2, 'Hello', 14
FROM `slot`
WHERE NOT EXISTS (
SELECT `id` FROM `slot`
WHERE `start` <= 1408141210 AND `end` >= 1408141206
AND `devices_id` = 14)
GROUP BY (1);
INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT 1408141208, 1408141214, 11, 2, 'Hello', 14
FROM `slot`
WHERE NOT EXISTS (
SELECT `id` FROM `slot`
WHERE `start` <= 1408141214 AND `end` >= 1408141208
AND `devices_id` = 14)
GROUP BY (1);
INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT 1408141216, 1408141220, 11, 2, 'Hello', 14
FROM `slot`
WHERE NOT EXISTS (
SELECT `id` FROM `slot`
WHERE `start` <= 1408141220 AND `end` >= 1408141216
AND `devices_id` = 14)
GROUP BY (1);
SELECT * FROM `slot`;
यह स्पष्ट रूप से आशावादी लॉकिंग का एक चरम उदाहरण है लेकिन अंत में बहुत कुशल है क्योंकि सभी केवल एक SQL निर्देश के साथ और डेटाबेस सर्वर और PHP कोड के बीच कम इंटरैक्शन (डेटा एक्सचेंज) के साथ किया जाता है। इसके अलावा व्यावहारिक रूप से कोई "वास्तविक" लॉकिंग नहीं है।
...या निराशावादी लॉकिंग के साथ
वही कोड स्पष्ट टेबल लॉक/अनलॉक निर्देशों के साथ एक अच्छा निराशावादी लॉकिंग कार्यान्वयन बन सकता है:
LOCK TABLE slot WRITE, dummy READ;
INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT @startTime, @endTime, @uid, @group, @message, @deviceId
FROM `dummy`
WHERE NOT EXISTS (
SELECT `id` FROM `slot`
WHERE `start` <= @endTime AND `end` >= @startTime
AND `devices_id` = @deviceId);
UNLOCK TABLES;
बेशक इस मामले में (निराशावादी लॉकिंग) चयन और INSERT को अलग किया जा सकता है और कुछ PHP कोड को बीच में निष्पादित किया जा सकता है। हालांकि यह कोड निष्पादित करने के लिए बहुत तेज़ रहता है (php के साथ कोई डेटा एक्सचेंज नहीं, कोई मध्यवर्ती PHP कोड नहीं) और इसलिए निराशावादी लॉक की अवधि सबसे कम संभव है। एप्लिकेशन को धीमा होने से बचाने के लिए निराशावादी लॉक को यथासंभव छोटा रखना एक महत्वपूर्ण बिंदु है।
वैसे भी आपको यह जानने के लिए प्रभावित रिकॉर्ड वापसी मूल्य की संख्या की जांच करने की आवश्यकता है कि क्या यह सफल हुआ है क्योंकि कोड व्यावहारिक रूप से समान है और इसलिए आपको उसी तरह सफलता/विफलता की जानकारी मिलती है।
यहां http://dev.mysql.com/doc/ रेफमैन/5.0/hi/insert-select.html वे कहते हैं कि "MySQL INSERT के लिए समवर्ती सम्मिलन की अनुमति नहीं देता ... चयन कथन" इसलिए इसे निराशावादी लॉक की आवश्यकता नहीं होनी चाहिए लेकिन वैसे भी यह एक अच्छा विकल्प हो सकता है यदि आपको लगता है कि यह MySQL के भविष्य के संस्करणों में बदल जाएगा।
मैं "आशावादी" हूं कि यह नहीं बदलेगा;-)