2009-09-26 24 views
7

मैं प्रतिबिंबित करने के लिए कि किसी दिए गए ग्राहक सत्र रिकॉर्ड एक बहु सत्र पर्यावरण के भीतर हासिल कर ली है (और अब यह आगे के अपडेट के मालिक) एक तालिका के एक ही रिकॉर्ड को अपडेट करना चाहते हैं। मैं इस मिल गया है अब तक:परमाणु अनन्य एसक्यूएल रिकॉर्ड अद्यतन

create procedure AcquireRow(
    @itemNo int,   -- Item ID to acquire 
    @sessNo int,   -- Session ID 
    @res  char(1) out) -- Result 
as 
begin 
    -- Attempt to acquire the row 
    update Items 
    set 
     State = 'A',  -- 'A'=Acquired 
     SessionID = @sessNo 
    where ItemID = @itemNo 
     and State = 'N'; -- 'N'=Not acquired 

    -- Verify that the session actually acquired the row 
    set @res = 'T';  -- 'T'=Success 
    if @@rowcount = 0 
    set @res = 'F';  -- 'F'=Failure 
end; 

बाहर चर @state'T' अगर प्रक्रिया को सफलतापूर्वक हासिल कर ली पंक्ति पर सेट किया जाता है, अन्यथा यह विफलता का संकेत करने के लिए 'F' सेट है।

मेरा प्रश्न: इस atomically काम करने की गारंटी है, ताकि एक ही सत्र सफलतापूर्वक (नवीनीकरण) पंक्ति का अधिग्रहण कई सत्रों एक ही समय में AcquireRow() फोन तो क्या होगा? या यह करने का एक बेहतर तरीका है? क्या मुझे एक स्पष्ट rowlock की आवश्यकता है?

संशोधित:
Remus के जवाब के आधार पर, मैं इस प्रकार कोड को पुनर्व्यवस्थित होगा:

set @res = 'F'; 
update ...; 
if @@rowcount > 0 
    set @res = 'T'; 

एक output खंड का उपयोग करना या बताए जिसके परिणामस्वरूप पंक्ति के ItemIDupdate भीतर एक चर को भी समझदारी होगी।

+0

SO पर एक बहुत ही समान प्रश्न पूछा गया है, लेकिन मुझे यह नहीं मिल रहा है .... –

+0

यह एक समान है लेकिन मेरे मन में नहीं था: http://stackoverflow.com/questions/574549/ कुशल लेनदेन-रिकॉर्ड-लॉकिंग –

उत्तर

9

@@ROWCOUNT गलत पाने के लिए बेहद आसान है। उदाहरण के लिए, आपके मामले में। MSDN से:

बयान है कि एक साधारण काम हमेशा @@ROWCOUNT मान 1 के लिए कोई पंक्ति नहीं ग्राहक के लिए भेजा जाता निर्धारित किया है। इन बयानों के उदाहरण हैं: SET @local_variable ...

सही आप तुरंत UPDATE के बाद @@ ROWCOUNT की जाँच करनी चाहिए होने के लिए। ROWLOCK का उपयोग करना सुरक्षित है लेकिन आवश्यक नहीं है। भले ही ऑप्टिमाइज़र पेज लॉक का उपयोग करने का फैसला करता है, 'अधिग्रहण' अर्थशास्त्र सही हैं।

मैं शायद, एक और दृष्टिकोण पसंद करेंगे अर्थात् UPDATE की OUTPUT खंड का उपयोग करें:

declare @updated table (ItemId int); 

update Items 
set ... 
output inserted.ItemId 
into @updated (ItemId) 
where ... 

यह योजना, अधिक त्रुटि सबूत और भी अधिक लचीला है के रूप में यह अज्ञात Itemid की प्राप्त करने के लिए अनुमति देता है: आईडी का अधिग्रहण @updated तालिका चर में रखा गया है और कॉलर पर वापस किया जा सकता है।

एक सामान्य नोट के रूप में, 'अधिग्रहण' के लिए वास्तविक, प्रतिबद्ध, अद्यतनों का उपयोग करके समस्याओं के साथ झुका हुआ है क्योंकि आप नहीं जानते कि वास्तव में कौन सी पंक्तियां अधिग्रहित की जाती हैं और कौन से लोगों को छोड़ दिया जाता है (क्लाइंट डिस्कनेक्ट या क्रैश हो गया/अधिग्रहण जारी ')। जबकि डेटाबेस इंजन पंक्तियों को अद्यतन करने, जब लेखन उत्पन्न होती है जो एक विशेष ताला में बदल जाता है की जरूरत है कि पढ़ रही है

एसक्यूएल सर्वर में
+0

धन्यवाद, मुझे '@@ rowcount' के उस विशेष छिपे खतरे के बारे में पता नहीं था। मेरे मूल कोड के पहले संस्करण में, मैंने 'अपडेट' से पहले' @ res' सेट किया था, इसलिए इसे उस समस्या को नहीं मिला था। प्रभावित पंक्ति की आईडी को कैप्चर करने के लिए मैंने 'output' या' set @updateID = ItemID = @ itemNo' का उपयोग करने पर भी विचार किया था, लेकिन इसके बारे में निश्चित नहीं था। जानकारी के लिए धन्यवाद। –

3

अद्यतन बयान एक अद्यतन ताला हासिल।

जब एक विशेष लॉक एक पंक्ति पर होता है, तो अन्य सभी लेन-देन को पढ़ने और लिखने से अवरुद्ध कर दिया जाता है (जब तक कि पढ़ने का लेनदेन अनजान अलगाव पढ़ा जाता है, या नोलोक संकेत का उपयोग किया जाता है)।

तो हाँ, जैसा कि यह खड़ा है, आपका अपडेट स्टेटमेंट एक परमाणु ऑटोोकॉमिटेड लेनदेन है, इसलिए इसे एक ही समय में कॉल करने वाले कई सत्रों के संबंध में ठीक होना चाहिए। यदि आप किसी भी कारण से इसे एकाधिक कथन में तोड़ना चाहते थे, तो आपको यह सुनिश्चित करना होगा कि आपने स्पष्ट रूप से अपने एसपी में एक लेनदेन बनाया है।

@@ ROWCOUNT और "अधिग्रहण" के सामान्य उपयोग के बारे में रीमस की टिप्पणियां हालांकि काफी ठोस सलाह हैं।

+0

ग्रेट अपडेट - क्या आपके पास एमएसडीएन के लिए कोई संदर्भ है या इसके लिए इसी तरह का? –

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