2010-11-10 13 views
5

मेरे .NET एप्लिकेशन के लिए इवेंट लॉग दिखाता है कि यह कभी-कभी SQL सर्वर से पढ़ने के दौरान deadlocks। यह आमतौर पर बहुत दुर्लभ होता है क्योंकि हम पहले से ही हमारे प्रश्नों को डेडलॉक्स से बचने के लिए अनुकूलित कर चुके हैं, लेकिन कभी-कभी वे कभी भी होते हैं। अतीत में, हमारे पास SqlCommand उदाहरण पर ExecuteReader फ़ंक्शन को कॉल करते समय कुछ डेडलॉक्स होते हैं। बस इस तरह फिर से क्वेरी चलाने के लिए, यह हमारे द्वारा जोड़े गए फिर से प्रयास करें कोड को ठीक करने के लिए:SqlDataReader के दौरान डेडलॉक अपवाद से पुनर्प्राप्त कैसे करें। पढ़ें()

//try to run the query five times if a deadlock happends 
int DeadLockRetry = 5; 

while (DeadLockRetry > 0) 
{ 
    try 
    { 
     return dbCommand.ExecuteReader(); 
    } 
    catch (SqlException err) 
    { 
     //throw an exception if the error is not a deadlock or the deadlock still exists after 5 tries 
     if (err.Number != 1205 || --DeadLockRetry == 0) 
      throw; 
    } 
} 

इस मामले में जहां गतिरोध पर अमल प्रारंभिक क्वेरी के दौरान हुआ के लिए बहुत अच्छी तरह से काम किया, लेकिन अब हम जबकि गतिरोध हो रही है SqlDataReader पर Read() फ़ंक्शन का उपयोग करके परिणामों के माध्यम से पुनरावृत्ति।

फिर से, मैं क्वेरी को अनुकूलित करने के बारे में चिंतित नहीं हूं, लेकिन केवल एक दुर्लभ मामले में पुनर्प्राप्त करने की कोशिश कर रहा हूं कि एक डेडलॉक होता है। मैं एक समान पुनः प्रयास प्रक्रिया का उपयोग करने के बारे में सोच रहा था। मैं अपनी खुद की कक्षा बना सकता हूं जो SqlDataReader से विरासत में आता है जो पुनः प्रयास कोड के साथ Read फ़ंक्शन को ओवरराइड करता है। इस तरह:

public class MyDataReader : SqlDataReader 
{ 
    public override bool Read() 
    { 
     int DeadLockRetry = 5; 
     while (DeadLockRetry > 0) 
     { 
      try 
      { 
       return base.Read(); 
      } 
      catch (SqlException ex) 
      { 
       if (ex.ErrorCode != 1205 || --DeadLockRetry == 0) 
        throw; 
      } 
     } 
     return false; 
    } 
} 

क्या यह सही दृष्टिकोण है? मैं यह सुनिश्चित करना चाहता हूं कि पाठक में रिकॉर्ड नहीं छोड़े गए हैं। डेडलॉक के बाद किसी भी पंक्ति को छोड़ने के बाद Read पुन: प्रयास कर रहे हैं? साथ ही, मुझे डेडलॉक स्थिति से बाहर निकलने के लिए डेटाबेस समय देने के लिए रीट्रीज़ के बीच Thread.Sleep पर कॉल करना चाहिए, या यह पर्याप्त है। इस मामले को पुन: पेश करना आसान नहीं है इसलिए मैं अपने किसी भी कोड को संशोधित करने से पहले इसके बारे में निश्चित होना चाहता हूं।

संपादित करें:

के रूप में अनुरोध किया है, मेरी स्थिति के बारे में कुछ और जानकारी: एक मामले में, मैं एक प्रक्रिया है कि एक प्रश्न है कि रिकॉर्ड आईडी अद्यतन करने की आवश्यकता है कि की एक सूची लोड करता है। फिर मैं Read फ़ंक्शन का उपयोग करके आईडी की उस सूची के माध्यम से पुन: प्रयास करता हूं और उस रिकॉर्ड पर एक अद्यतन प्रक्रिया चलाता हूं, जो अंततः डेटाबेस में उस रिकॉर्ड के लिए एक मान अपडेट करेगा। (नहीं, प्रारंभिक क्वेरी में अद्यतन करने का कोई तरीका नहीं है, लौटाए गए प्रत्येक रिकॉर्ड के लिए कई अन्य चीजें होती हैं)। यह कोड थोड़ी देर के लिए ठीक काम कर रहा है, लेकिन हम प्रत्येक रिकॉर्ड के लिए काफी कोड चला रहे हैं, इसलिए मैं कल्पना कर सकता हूं कि इनमें से एक प्रक्रिया प्रारंभिक तालिका को पढ़ने के लिए लॉक बना रही है।

कुछ विचारों के बाद, परिणाम संग्रहित करने के लिए डेटा संरचना का उपयोग करने के लिए स्कॉटी के सुझाव से इस स्थिति को ठीक किया जाएगा। मैं List<int> में लौटा आईड्स स्टोर कर सकता हूं और उसके माध्यम से लूप कर सकता हूं। इस तरह पंक्तियों पर ताले तुरंत हटा दिए जा सकते हैं।

हालांकि, मुझे अभी भी यह जानने में दिलचस्पी होगी कि पढ़ने पर डेडलॉक्स से पुनर्प्राप्त करने का सामान्य तरीका है या नहीं।

+0

आप अपने डीबी उपयोग के बारे में अधिक जानकारी देने के किया जा सका:

function DoWork() { using (TransactionScope scope = new TransactionScope(...)) { cmd = new SqlCommand("select ..."); using (DataReader rdr = cmd.ExecuteReader()) { while(rdr.Read()) { ... process each record } } scope.Complete(); } } 

आप पूरेDoWork कॉल पुन: प्रयास करने के लिए है? डेटा पढ़ने के दौरान एक डेडलॉक प्राप्त करना अजीब बात है। इसका मतलब है कि आपका कोड पहले से ही अन्य डेटा के लिए कुछ ताले रख रहा है और एक अन्य लेनदेन ने जो कुछ भी आप पढ़ने की कोशिश कर रहे हैं उसे बंद कर दिया है और उस डेटा की प्रतीक्षा कर रहा है जिसे आपने पहले एक्सेस किया था। क्या आप किसी अन्य लेनदेन पर ExecuteReader को कॉल कर सकते हैं? – Timores

उत्तर

4

आपका पूरा लेनदेन डेडलॉक में खो गया है। आपको डेटा रीडर पढ़ने के स्तर से ऊपर वे से स्क्रैच से पुनरारंभ करना होगा। आप कहते हैं कि आप कुछ रिकॉर्ड पढ़ते हैं, फिर उन्हें लूप में अपडेट करें।आप फिर से रिकॉर्ड पढ़ने के साथ पुनः आरंभ करना:

retries = 0; 
success = false; 
do { 
try { 
    DoWork(); 
    success = true; 
} 
catch (SqlException e) { 
    if (can retry e) { 
    ++retries; 
    } 
    else { 
    throw; 
    } 
} 
} while (!success); 
+0

यह। आप बस पुनः पढ़ने की कोशिश नहीं कर सकते हैं, आपको कमांड को फिर से चालू करने की आवश्यकता है। लेकिन आपको निश्चित रूप से 3-5 अधिकतम पर रीट्रीज़ की संख्या सीमित करनी चाहिए, यह एसक्यूएल सर्वर को डेडलॉक्स को संभालने के लिए कुछ समय लेता है। –

+0

ठीक है धन्यवाद, यही वह है जिसे मैं ढूंढ रहा था। हमारे पास एक सारणीबद्ध डेटा परत है जो हमारे सभी पढ़े गए प्रश्नों के लिए IDataReaders लौटाती है, और फिर हमारे तर्क कोड पाठकों का उपयोग करता है। तो मेरे आवेदन में आपके पढ़ने के कोडिंग के रूप में सुझाव दिया आसान नहीं है। मैं एक सामान्य समाधान की उम्मीद कर रहा था, लेकिन ऐसा लगता है कि यह संभव नहीं है। मैं विशिष्ट मामलों के लिए इस सुझाव का उपयोग करने पर विचार करूंगा जो कभी-कभी डेडलॉक्स पैदा कर रहे हैं। आपके सुझावों के लिए सभी को धन्यवाद! – InvisibleBacon

0

क्या आप संभवतः डेटा रीडर के बजाय डेटासेट या डेटाटेबल्स का उपयोग करने पर विचार कर सकते हैं?

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

+0

मुझे पूरा यकीन है कि डेटाटेबल या सेट का उपयोग करना वही भेद्यता होगी। .NET उपयोग डेटाटेबल को भरने के लिए आंतरिक रूप से पढ़ें नहीं? मैं निश्चित रूप से एक नियंत्रित वातावरण में इसका परीक्षण करने में सक्षम होना चाहूंगा। यकीन नहीं है कि वास्तव में deadlocks का कारण क्या है, तो यह मुश्किल होगा। – InvisibleBacon

+0

आपको विशेष रूप से डेडलॉक के लिए परीक्षण करने की आवश्यकता नहीं है। यदि आप एक नियंत्रित वातावरण में हैं, तो आप SQL सर्वर को एक सेकंड के लिए नीचे ले जा सकते हैं और उस त्रुटि को जाल कर सकते हैं। यह आपको कम से कम बताएगा कि रिकॉर्ड फिर से पढ़ा या त्याग दिया गया है या नहीं। – Scottie

+0

हां, डेटासेट एक ही पढ़ने के तंत्र का उपयोग करते हैं, लेकिन मुझे आश्चर्य है कि क्या एमएस पढ़ने के दौरान पहले से ही डेडलॉक कोड है? – Scottie