एक सिंगल SqlException
(मई) एकाधिक SQL सर्वर त्रुटियों को लपेटता है। आप उनके माध्यम से Errors
के साथ पुनरावृति कर सकते हैं संपत्ति। प्रत्येक त्रुटि SqlError
है :
foreach (SqlError error in exception.Errors)
प्रत्येक SqlError
एक Class
है संपत्ति का उपयोग आप मोटे तौर पर यह निर्धारित करने के लिए कर सकते हैं कि आप पुनः प्रयास कर सकते हैं या नहीं (और यदि आप पुनः प्रयास करते हैं तो आपको कनेक्शन भी फिर से बनाना है)। एमएसडीएन से:
Class
<10 आपके द्वारा पास की गई जानकारी में त्रुटियों के लिए है (शायद) यदि आप पहले इनपुट सही नहीं करते हैं तो आप पुनः प्रयास नहीं कर सकते।Class
11 से 16 तक "उपयोगकर्ता द्वारा उत्पन्न" होते हैं, तो शायद फिर से आप कुछ भी नहीं कर सकते हैं यदि उपयोगकर्ता पहले अपने इनपुट को सही नहीं करता है। कृपया ध्यान दें कि कक्षा 16 में कई अस्थायी शामिल हैं त्रुटियों और कक्षा 13 गतिरोध के लिए है (ईवीजेड के लिए धन्यवाद) इसलिए यदि आप इन कक्षाओं को एक-एक करके संभालते हैं तो आप इन कक्षाओं को बाहर कर सकते हैं।Class
17 से 24 तक सामान्य हार्डवेयर/सॉफ़्टवेयर त्रुटियाँ हैं और आप पुनः प्रयास कर सकते हैं। जबClass
20 या अधिक है आपको कनेक्शन को फिर से बनाना भी। 22 और 23 गंभीर हार्डवेयर/सॉफ़्टवेयर त्रुटियाँ हो सकती हैं, 24 एक मीडिया त्रुटि को इंगित करता है (कुछ उपयोगकर्ता को चेतावनी दी जानी चाहिए लेकिन यदि यह केवल "अस्थायी" त्रुटि थी तो आप पुनः प्रयास कर सकते हैं)।
आप यहां प्रत्येक कक्षा का अधिक विस्तृत विवरण प्राप्त कर सकते हैं।
सामान्य तौर पर यदि आप उनकी कक्षा के साथ त्रुटियों को संभालते हैं तो आपको प्रत्येक त्रुटि को ठीक से जानने की आवश्यकता नहीं होगी (error.Number
का उपयोग करके) संपत्ति या exception.Number
जो पहले SqlError
. के लिए सिर्फ एक शॉर्टकट है उस सूची में)। इसका एक दोष यह है कि जब यह उपयोगी नहीं होता है तो आप पुन:प्रयास कर सकते हैं (या त्रुटि को पुनर्प्राप्त नहीं किया जा सकता है)। मेरा सुझाव है कि दो चरणों वाला तरीका :
- ज्ञात त्रुटि कोड की जांच करें (
SELECT * FROM master.sys.messages
के साथ त्रुटि कोड सूचीबद्ध करें ) यह देखने के लिए कि आप क्या संभालना चाहते हैं (जानना कैसे)। उस दृश्य में सभी समर्थित भाषाओं के संदेश हैं, इसलिए आपको उन्हेंmsglangid
. द्वारा फ़िल्टर करने की आवश्यकता हो सकती है कॉलम (उदाहरण के लिए अंग्रेजी के लिए 1033)। - अन्य सभी चीज़ों के लिए त्रुटि वर्ग पर भरोसा करें,
Class
. के समय पुनः प्रयास करें 13 या 16 से अधिक है (और 20 या अधिक होने पर फिर से कनेक्ट हो रहा है)। - 21 (22, 23 और 24) से अधिक गंभीरता वाली त्रुटियां गंभीर त्रुटियां हैं और थोड़ी प्रतीक्षा से वे समस्याएं ठीक नहीं होंगी (डेटाबेस स्वयं भी क्षतिग्रस्त हो सकता है)।
उच्च वर्गों के बारे में एक शब्द। इन त्रुटियों को कैसे संभालना आसान नहीं है और यह कई कारकों पर निर्भर करता है (जोखिम प्रबंधन . सहित) आपके आवेदन के लिए)। एक सरल पहले चरण के रूप में मैं 22, 23, और 24 के लिए पुनः प्रयास नहीं करूँगा जब एक लेखन कार्य करने का प्रयास किया जाता है:यदि डेटाबेस, फ़ाइल सिस्टम या मीडिया गंभीर रूप से क्षतिग्रस्त हैं तो नया डेटा लिखना डेटा अखंडता को और भी खराब कर सकता है (एसक्यूएल सर्वर बेहद सावधान है गंभीर परिस्थितियों में भी किसी प्रश्न के लिए DB से समझौता न करें)। एक क्षतिग्रस्त सर्वर, यह आपके डीबी नेटवर्क आर्किटेक्चर पर निर्भर करता है, यहां तक कि हॉट-स्वैप भी हो सकता है (स्वचालित रूप से, निर्दिष्ट समय के बाद, या जब एक निर्दिष्ट ट्रिगर निकाल दिया जाता है)। हमेशा सलाह लें और अपने डीबीए के करीब काम करें।
पुन:प्रयास करने की रणनीति उस त्रुटि पर निर्भर करती है जिसे आप संभाल रहे हैं:मुक्त संसाधन, एक लंबित ऑपरेशन के पूरा होने की प्रतीक्षा करें, एक वैकल्पिक कार्रवाई करें, आदि। सामान्य तौर पर आपको केवल तभी प्रयास करना चाहिए जब सभी त्रुटियां "पुन:प्रयास करने योग्य" हैं:
bool rebuildConnection = true; // First try connection must be open
for (int i=0; i < MaximumNumberOfRetries; ++i) {
try {
// (Re)Create connection to SQL Server
if (rebuildConnection) {
if (connection != null)
connection.Dispose();
// Create connection and open it...
}
// Perform your task
// No exceptions, task has been completed
break;
}
catch (SqlException e) {
if (e.Errors.Cast<SqlError>().All(x => CanRetry(x))) {
// What to do? Handle that here, also checking Number property.
// For Class < 20 you may simply Thread.Sleep(DelayOnError);
rebuildConnection = e.Errors
.Cast<SqlError>()
.Any(x => x.Class >= 20);
continue;
}
throw;
}
}
try
में सब कुछ लपेटें /finally
कनेक्शन को ठीक से निपटाने के लिए। इस सरल-नकली-भोले CanRetry()
. के साथ समारोह:
private static readonly int[] RetriableClasses = { 13, 16, 17, 18, 19, 20, 21, 22, 24 };
private static bool CanRetry(SqlError error) {
// Use this switch if you want to handle only well-known errors,
// remove it if you want to always retry. A "blacklist" approach may
// also work: return false when you're sure you can't recover from one
// error and rely on Class for anything else.
switch (error.Number) {
// Handle well-known error codes,
}
// Handle unknown errors with severity 21 or less. 22 or more
// indicates a serious error that need to be manually fixed.
// 24 indicates media errors. They're serious errors (that should
// be also notified) but we may retry...
return RetriableClasses.Contains(error.Class); // LINQ...
}
यहां गैर-महत्वपूर्ण त्रुटियों की सूची खोजने के कुछ बहुत ही मुश्किल तरीके हैं।
आम तौर पर मैं यह सब (बॉयलरप्लेट) कोड एक विधि में एम्बेड करता हूं (जहां मैं छिपा सकता हूं सभी गंदी चीज़ें कनेक्शन बनाने/निपटान/पुन:बनाने के लिए किया गया) इस हस्ताक्षर के साथ:
public static void Try(
Func<SqlConnection> connectionFactory,
Action<SqlCommand> performer);
इस तरह इस्तेमाल करने के लिए:
Try(
() => new SqlConnection(connectionString),
cmd => {
cmd.CommandText = "SELECT * FROM master.sys.messages";
using (var reader = cmd.ExecuteReader()) {
// Do stuff
}
});
कृपया ध्यान दें कि कंकाल (त्रुटि पर पुनः प्रयास करें) का उपयोग तब भी किया जा सकता है जब आप SQL सर्वर के साथ काम नहीं कर रहे हों (वास्तव में इसका उपयोग I/O और नेटवर्क से संबंधित सामग्री जैसे कई अन्य कार्यों के लिए किया जा सकता है, इसलिए मैं एक सामान्य फ़ंक्शन लिखने का सुझाव दूंगा और इसे बड़े पैमाने पर पुन:उपयोग करने के लिए)।