जैसा कि पॉल लिखते हैं:नहीं, यह सुरक्षित नहीं है , जिसके लिए मैं अनुभवजन्य साक्ष्य जोड़ना चाहूंगा:एक तालिका बनाएं Table_1
एक फ़ील्ड के साथ ID
और मान के साथ एक रिकॉर्ड 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
मेरे SQL सर्वर 2008 पर, एक आईडी (662
) दो बार बनाया गया था। इस प्रकार, एकल कथनों पर लागू डिफ़ॉल्ट अलगाव स्तर नहीं है पर्याप्त।
संपादित करें:स्पष्ट रूप से, INSERT
को लपेटकर BEGIN TRANSACTION
. के साथ और COMMIT
इसे ठीक नहीं करेगा, क्योंकि लेन-देन के लिए डिफ़ॉल्ट अलगाव स्तर अभी भी READ COMMITTED
है है, जो पर्याप्त नहीं है। ध्यान दें कि लेन-देन अलगाव स्तर को REPEATABLE READ
पर सेट करें भी है पर्याप्त नहीं। उपरोक्त कोड को सुरक्षित बनाने का एकमात्र तरीका जोड़ना है
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
शीर्ष पर। हालांकि, इसने मेरे परीक्षणों में समय-समय पर गतिरोध पैदा किया।
संपादित करें:मैंने पाया एकमात्र समाधान जो सुरक्षित है और गतिरोध उत्पन्न नहीं करता है (कम से कम मेरे परीक्षणों में) स्पष्ट रूप से तालिका को विशेष रूप से लॉक करना है (डिफ़ॉल्ट लेनदेन अलगाव स्तर यहां पर्याप्त है)। हालांकि सावधान रहें; यह समाधान मार हो सकता है प्रदर्शन:
...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...