2008-11-26 4 views
19

मेरे पास एक वर्ग 'डेटाबेस' है जो ADO.net के लिए एक रैपर के रूप में काम करता है। उदाहरण के लिए, जब मुझे किसी प्रक्रिया को निष्पादित करने की आवश्यकता होती है, तो मैं डेटाबेस को कॉल करता हूं। निष्पादन प्रक्रिया (प्रक्रिया नाम, पैरामीटर औरItsValues)।एडीओ के साथ सी # में कुशल एसक्यूएल सर्वर डेडलॉक हैंडलिंग कैसे प्राप्त करें?

हम SQL Server 2000 में डेडलॉक स्थितियों के साथ गंभीर समस्याएं अनुभव कर रहे हैं। हमारी टीम का हिस्सा एसक्यूएल कोड और लेनदेन पर काम कर रहा है ताकि इन घटनाओं को कम किया जा सके, लेकिन मैं इस डेटाबेस वर्ग को डेडलॉक स्थितियों के खिलाफ मजबूत बनाने के बारे में सोच रहा हूं।

हम चाहते हैं कि डेडलॉक पीड़ित शायद कुछ समय के बाद पुनः प्रयास करें, लेकिन मुझे नहीं पता कि यह संभव है या नहीं। यहां उपयोग की जाने वाली विधि के लिए कोड है:

public int ExecuteQuery(string query) 
{ 
    int rows = 0; 

    try 
    { 
     Command.Connection = Connection; 
     Command.CommandType = CommandType.Text; 

     if(DatabaseType != enumDatabaseType.ORACLE) 
      Command.CommandText = query; 
     else 
      Command.CommandText ="BEGIN " + query + " END;"; 



     if (DatabaseType != enumDatabaseType.SQLCOMPACT) 
      Command.CommandTimeout = Connection.ConnectionTimeout; 

     if (Connection.State == ConnectionState.Closed) 
      Connection.Open(); 

     rows = Command.ExecuteNonQuery(); 
    } 
    catch (Exception exp) 
    { 
     //Could I add here any code to handle it? 
     throw new Exception(exp.Message); 
    } 
    finally 
    { 
     if (Command.Transaction == null) 
     { 
      Connection.Close(); 
      _connection.Dispose(); 
      _connection = null; 
      Command.Dispose(); 
      Command = null; 
     } 
    } 
    return rows; 
} 

क्या मैं कैच ब्लॉक के अंदर यह हैंडलिंग कर सकता हूं?

उत्तर

31

सबसे पहले, मैं अपने एसक्यूएल 2000 कोड की समीक्षा करने और क्यों इस गतिरोध हो रहा है की तह तक पहुंचने होगा पर समाधान नहीं कर सकते । इसे ठीक करने से बड़ी समस्या छिपी जा सकती है (उदा। अनुपलब्ध इंडेक्स या खराब क्वेरी)।

दूसरा मैं deadlocking कथन की पुष्टि करने के लिए अपनी वास्तुकला की समीक्षा करेगी वास्तव में कहा जा है कि अक्सर की जरूरत है (select count(*) from bob 100 बार एक दूसरे के नाम से जाना है?)।

हालांकि, अगर आपको वास्तव में कुछ डेडलॉक समर्थन की आवश्यकता है और आपके SQL या आर्किटेक्चर में कोई त्रुटि नहीं है तो निम्न पंक्तियों के साथ कुछ प्रयास करें। (नोट: मैं एक प्रणाली प्रति सेकंड प्रश्नों के हजारों समर्थन करने के लिए इस तकनीक का प्रयोग करना पड़ा है और काफी मुश्किल से ही गतिरोध पर मारते थे)

int retryCount = 3; 
bool success = false; 
while (retryCount > 0 && !success) 
{ 
    try 
    { 
    // your sql here 
    success = true; 
    } 
    catch (SqlException exception) 
    { 
    if (exception.Number != 1205) 
    { 
     // a sql exception that is not a deadlock 
     throw; 
    } 
    // Add delay here if you wish. 
    retryCount--; 
    if (retryCount == 0) throw; 
    } 
} 
+0

'थ्रेड स्लीप (100);' पुनः प्रयास करें 'के बाद पुनः प्रयास लूप में थोड़ी देर देरी पर विचार करें;' पुनः प्रयास करें ';' SQL सर्वर को इतना कठिन मारने से रोकने के लिए। –

2

यदि आपको डेडलॉक्स के साथ समस्याएं आ रही हैं, तो यह देखना बेहतर होगा कि SQL कोड क्या कर रहा है। उदाहरण के लिए, लॉक-एस्केलेशन डेडलॉक्स बनाने के लिए बहुत आसान है यदि आपके पास क्रमिक अलगाव स्तर (या जो कुछ भी आपके rdbms में समतुल्य है) - और कुछ तरीकों से कम किया जा सकता है, जैसे प्रश्नों को पुन: क्रमबद्ध करना, या (SQL सर्वर में कम से कम) (UPDLOCK) का उपयोग पहले लिखने के लिए लॉक लेने के लिए (इसलिए आपको एक प्रतिस्पर्धी रीड-लॉक नहीं मिलता है)।

पुन: प्रयास करने के लिए मिश्रित होने जा रहा है ... उदाहरण के लिए, यदि आप एक लेनदेनस्कोप में हैं, तो यह पहले से ही निरस्त हो सकता है। लेकिन सिर्फ शुद्ध स्तर पर - अगर मुझे डीबी से बात करने में समस्याएं आती हैं तो मैं चाहता हूं कि मेरा कोड घबराए और जल्दी घबराए ... इस विशेष परिदृश्य में पुनः प्रयास करें।

+0

हम सभी एसक्यूएल कोड और लेनदेन पर विचार कर रहे हैं, यह किया जा रहा है, हम केवल सी # को याद करके डेडलॉक धोखा देने की कोशिश नहीं कर रहे हैं। लेकिन समेकन डेडलॉक पीड़ितों को बना सकता है, और इसके कारण हम अपने ऐप्स को और अधिक मजबूत बनाना चाहते हैं जब ऐसा होता है। –

+0

विक्टर - आप डेटा परत पर उन्हें हल करके deadlocks के साथ सौदा कर सकते हैं और करना चाहिए। एक बार हल हो जाने पर, आपको सी # में कुछ भी करने की ज़रूरत नहीं है। –

+5

@ डेव - यह तर्कसंगत रूप से अत्यधिक सरल –

5

यदि डेटा परत पर डेडलॉक हल किया जा सकता है, तो यह निश्चित रूप से जाने का तरीका है। संकेतों को लॉक करना, मॉड्यूल के तरीके को फिर से डिजाइन करना और इसी तरह से। नोलॉक पैनासिया नहीं है - कभी-कभी लेनदेन संबंधी अखंडता के कारणों के लिए उपयोग करना संभव नहीं है और मेरे पास सभी प्रासंगिक तालिकाओं के साथ सीधे (हालांकि जटिल) डेटा पढ़ने के मामले हैं, जो अभी भी अन्य प्रश्नों पर ब्लॉक का कारण बनता है।

वैसे भी - यदि आप इसे जो भी कारण के लिए डेटा परत, कैसे के बारे में

bool OK = false; 
Random Rnd = new Random(); 

while(!OK) 
{ 
    try 
    { 
     rows = Command.ExecuteNonQuery(); 
     OK = true; 
    } 
    catch(Exception exDead) 
    { 
     if(exDead.Message.ToLower().Contains("deadlock")) 
      System.Threading.Thread.Sleep(Rnd.Next(1000, 5000)); 
     else 
      throw exDead; 
    } 
} 
+0

मुझे उपर्युक्त समाधान का उपयोग करने में दिलचस्पी है, लेकिन यह मेरे बारे में अधिक जानकारी की सराहना करेगा कि यह मेरे मामले के लिए वास्तव में कैसे काम कर सकता है। – Kobojunkie

+2

यादृच्छिक टाइमर के लिए अपवोट, सैम समाधान एसक्यूएल सर्वर – DeveloperChris

19

@ सैम प्रतिक्रिया पर बिल्डिंग, मैं एक सामान्य प्रयोजन फिर से प्रयास करें आवरण विधि मौजूद:

private static T Retry<T>(Func<T> func) 
{ 
    int count = 3; 
    TimeSpan delay = TimeSpan.FromSeconds(5); 
    while (true) 
    { 
     try 
     { 
      return func(); 
     } 
     catch(SqlException e) 
     { 
      --count; 
      if (count <= 0) throw; 

      if (e.Number == 1205) 
       _log.Debug("Deadlock, retrying", e); 
      else if (e.Number == -2) 
       _log.Debug("Timeout, retrying", e); 
      else 
       throw; 

      Thread.Sleep(delay); 
     } 
    } 
} 

private static void Retry(Action action) 
{ 
    Retry(() => { action(); return true; }); 
} 

// Example usage 
protected static void Execute(string connectionString, string commandString) 
{ 
    _log.DebugFormat("SQL Execute \"{0}\" on {1}", commandString, connectionString); 

    Retry(() => { 
     using (SqlConnection connection = new SqlConnection(connectionString)) 
     using (SqlCommand command = new SqlCommand(commandString, connection)) 
      command.ExecuteNonQuery(); 
    }); 
} 

protected static T GetValue<T>(string connectionString, string commandString) 
{ 
    _log.DebugFormat("SQL Scalar Query \"{0}\" on {1}", commandString, connectionString); 

    return Retry(() => { 
     using (SqlConnection connection = new SqlConnection(connectionString)) 
     using (SqlCommand command = new SqlCommand(commandString, connection)) 
     { 
      object value = command.ExecuteScalar(); 
      if (value is DBNull) return default(T); 
      return (T) value; 
     } 
    }); 
} 
संबंधित मुद्दे