2010-01-03 11 views
6

this SO question पर मेरे उत्तर में मैं एक एकल प्रविष्टि कथन का उपयोग करने का सुझाव देता हूं, एक चयन के साथ जो नीचे दिखाया गया है, जैसा कि नीचे दिखाया गया है।tsql में समेकन के मामले में एक चयन कथन सुरक्षित के साथ एक सम्मिलित है?

Insert Into VersionTable 
(Id, VersionNumber, Title, Description, ...) 
Select @ObjectId, max(VersionNumber) + 1, @Title, @Description 
From VersionTable 
Where Id = @ObjectId 

मैं इस सुझाव दिया है क्योंकि मैं मानना ​​है कि इस बयान का उद्देश्य एक ही आईडी के लिए एक और डालने एक ही समय में चलाया जाता है, तो संगामिति के मामले में सुरक्षित है, कि में, डुप्लिकेट संस्करण होने का कोई मौका नहीं है संख्या।

क्या मैं सही हूँ?

उत्तर

2

मुझे लगता है कि आप धारणा गलत हैं। जब आप VersionNumber तालिका से पूछते हैं, तो आप केवल पंक्ति पर एक पठन लॉक डाल रहे हैं। यह अन्य उपयोगकर्ताओं को एक ही पंक्ति से एक ही पंक्ति को पढ़ने से नहीं रोकता है। इसलिए, दो प्रक्रियाओं के लिए एक ही समय में संस्करण संख्या तालिका में एक ही पंक्ति को पढ़ने और समान संस्करण संख्या मूल्य उत्पन्न करना संभव है।

+0

क्षमा रैंडी, मैं अपने एसक्यूएल लिखने में कोई गलती नहीं थी। सम्मिलित करें और चयन एक ही टेबल पर हैं। क्या यह आपका जवाब बदलता है? –

+0

@ डेविड - मेरा जवाब नहीं बदलता है। अभी भी पंक्ति को पढ़ा जा रहा है, केवल उस पर एक लॉक लॉक होगा, न कि एक लिखित लॉक। इसलिए, यह अभी भी संभव है दो प्रक्रिया एक ही पंक्ति को एक ही पंक्ति में पढ़ सकती है, और एक ही आईडी मान उत्पन्न कर सकती है। इसे सुरक्षित बनाने के लिए, मुझे विश्वास है कि इसे होने से रोकने के लिए आपको अलगाव स्तर को Serializable (या दोहराने योग्य पढ़ने) में सेट करने की आवश्यकता है। –

4

पढ़ने के लिए डिफ़ॉल्ट अलगाव इस असुरक्षित बनाता है, यदि इनमें से दो सही पैराल में चलते हैं तो आपको डुप्लिकेट मिलेगा क्योंकि कोई रीड लॉक लागू नहीं होता है।

आपको इसे सुरक्षित बनाने के लिए पुनरावर्तनीय पढ़ने या सरलीकृत अलगाव स्तर की आवश्यकता है।

+1

डालने, चयन के साथ parallell में नहीं चल सकता, क्योंकि यह चयन – Andomar

+1

डेटा का उपयोग करता मेरा मतलब है दो उपयोगकर्ताओं समवर्ती क्वेरी को क्रियान्वित। –

+0

'SERIALIZABLE' काम करता है, लेकिन' repeatable READ' निश्चित रूप से पर्याप्त नहीं है (अभी भी अपने परीक्षण कोड में डुप्लिकेट का कारण बनता है)। – Heinzi

0
  • आप इसे लागू करने के लिए पर (क्रमांक, VersionNumber) एक अनूठा बाधा जरूरत

  • मैं चप्पू-आंकड़ा का उपयोग करेंगे, XLOCK बंद कर दिया पंक्ति जहां

  • गणना पढ़ने अन्य लोक ब्लॉक करने के लिए संकेत या एक TRY/कैच में INSERT लपेटें। अगर मैं एक नकली मिलता है, पुन: प्रयास करें ...

12

के रूप में पॉल लिखते हैं: नहीं, यह सुरक्षित नहीं है, जिसके लिए मैं अनुभवजन्य साक्ष्य जोड़ना चाहते हैं: एक क्षेत्र 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... 
+0

इस हेनज़ी के लिए धन्यवाद, यह काफी निश्चित दिखता है - मैं इसे स्वयं परीक्षण करने के तरीके के बारे में सोचने की कोशिश कर रहा हूं, लूप का उपयोग करने के बारे में सोचा नहीं था। –

+0

ओह - और कल से मेरे रास्ते पर +1 है, मैं आज के लिए upvotes से बाहर चला गया है। –

+0

मुझे समझ में नहीं आता कि यह पाश डुप्लीकेट क्यों उत्पन्न करेगा, यह निश्चित रूप से इमो नहीं होना चाहिए। मैं इसका परीक्षण करने जा रहा हूँ! –

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