के रूप में पॉल लिखते हैं: नहीं, यह सुरक्षित नहीं है, जिसके लिए मैं अनुभवजन्य साक्ष्य जोड़ना चाहते हैं: एक क्षेत्र ID
और एक के साथ एक मेज Table_1
बनाएं मूल्य 0
के साथ रिकॉर्ड करें। फिर दो प्रबंधन स्टूडियो क्वेरी खिड़कियों में एक साथ निम्नलिखित कोड निष्पादित करें:
declare @counter int
set @counter = 0
while @counter < 1000
begin
set @counter = @counter + 1
INSERT INTO Table_1
SELECT MAX(ID) + 1 FROM Table_1
end
तब निष्पादित
SELECT ID, COUNT(*) FROM Table_1 GROUP BY ID HAVING COUNT(*) > 1
मेरी एसक्यूएल सर्वर 2008 पर, एक आईडी (662
) दो बार बनाया गया था। इस प्रकार, एकल कथन पर लागू डिफ़ॉल्ट अलगाव स्तर पर्याप्त नहीं है।
संपादित करें: जाहिर है, लपेटकर BEGIN TRANSACTION
और COMMIT
साथ INSERT
, यह ठीक नहीं होगा लेन-देन के लिए डिफ़ॉल्ट अलगाव स्तर अभी भी READ COMMITTED
है के बाद से है, जो पर्याप्त नहीं है। ध्यान दें कि लेनदेन अलगाव स्तर REPEATABLE READ
पर भी पर्याप्त नहीं है। उपरोक्त कोड सुरक्षित बनाने के लिए एक ही रास्ता शीर्ष पर
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
जोड़ना है। हालांकि, यह हर बार और फिर मेरे परीक्षणों में deadlocks का कारण बनता है।
संपादित करें: एकमात्र समाधान मैंने पाया जो सुरक्षित और गतिरोध का उत्पादन नहीं करता है (कम से कम मेरे परीक्षणों में) स्पष्ट रूप से विशेष रूप से तालिका लॉक करने के लिए (डिफ़ॉल्ट लेनदेन अलगाव स्तर यहाँ पर्याप्त है) है। हालांकि सावधान रहें; इस समाधान प्रदर्शन को मारने सकता है:
...loop stuff...
BEGIN TRANSACTION
SELECT * FROM Table_1 WITH (TABLOCKX, HOLDLOCK) WHERE 1=0
INSERT INTO Table_1
SELECT MAX(ID) + 1 FROM Table_1
COMMIT
...loop end...
क्षमा रैंडी, मैं अपने एसक्यूएल लिखने में कोई गलती नहीं थी। सम्मिलित करें और चयन एक ही टेबल पर हैं। क्या यह आपका जवाब बदलता है? –
@ डेविड - मेरा जवाब नहीं बदलता है। अभी भी पंक्ति को पढ़ा जा रहा है, केवल उस पर एक लॉक लॉक होगा, न कि एक लिखित लॉक। इसलिए, यह अभी भी संभव है दो प्रक्रिया एक ही पंक्ति को एक ही पंक्ति में पढ़ सकती है, और एक ही आईडी मान उत्पन्न कर सकती है। इसे सुरक्षित बनाने के लिए, मुझे विश्वास है कि इसे होने से रोकने के लिए आपको अलगाव स्तर को Serializable (या दोहराने योग्य पढ़ने) में सेट करने की आवश्यकता है। –