關於SQL Server的錯誤嚴重性級別的說明,強烈認真看一下下面的兩個鏈接
脫機幫助
ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.zh-CHS/sqlerrm9/html/3e7f5925-6edd-42e1-bf17-f7deb03993a7.htm
在線幫助
http://technet.microsoft.com/zh-cn/library/ms164086.aspx
簡而言之,SQL Server的錯誤嚴重性分為三個等級
1. 輕微錯誤 :嚴重性級別為0-10
2. 中等錯誤 :嚴重性級別為11-19
3. 嚴重錯誤 :嚴重性級別為20-25
SQL Server保存的所有錯誤消息是可以通過檢索sys.messages這個視圖來查看的,如下
為什么需要說這個呢?是因為我們需要知道不同的錯誤嚴重性級別所導致的行為是不一樣的
1. 輕微錯誤 :嚴重性級別為0-10 ==》默認情況下不會給客戶程序發送錯誤消息,繼續工作。也就是說它無法被CATCH到
2. 中等錯誤 :嚴重性級別為11-19 ==》能夠被CATCH到(不管是在T-SQL里面還是在客戶程序里面)
3. 嚴重錯誤 :嚴重性級別為20-25 ==》SQL Server將強制把連接關掉。很顯然這也不可能被CATCH到
關於在T-SQL中使用TRY...CATCH處理異常,請參考下面的鏈接
http://technet.microsoft.com/zh-cn/library/ms179296.aspx
關於在客戶端程序中處理異常,分兩種情況
1. 對於錯誤嚴重性級別在11-19之間的,能夠被TRY...CATCH到SQLException類型,然后可以對其進行處理
http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlexception(VS.80).aspx
2. 對於錯誤嚴重性級別在0-10之間的系統錯誤,或者通過PRINT語句發出的消息,或者通過RAISERROR語句發出的錯誤,如果需要在客戶程序里面處理,那么應該編寫Connection對象的InfoMessage事件
http://msdn.microsoft.com/zh-tw/library/a0hee08w.aspx
關於infoMessage事件,因為它可以接受PRINT語句的輸出消息,所以也有朋友用它來跟蹤存儲過程的進度等等,下面就有一個范例
http://www.cnblogs.com/hackzai/archive/2005/04/07/133635.html
還有一個屬性很有意思,FireInfoMessageEventOnUserErrors 。這個屬性為true,那么除了0-10的會被該事件處理,11-19的也可以通過該事件來處理,而不需要用TRY...CATCH
下面是一個例子
private void btTest_Click(object sender, EventArgs e) { using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString)) { conn.FireInfoMessageEventOnUserErrors = true; conn.InfoMessage += new SqlInfoMessageEventHandler(conn_InfoMessage); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "DROP TABLE TABLE1"; //這里我是故意讓它出錯,因為表不存在。由於前面設置了FireInfoMessageEventOnUserErrors為true,所以會自動由infoMessage事件處理 conn.Open(); cmd.ExecuteNonQuery(); cmd.CommandText = "RAISERROR('This is the message from the RAISERROR statement', 10, 1)"; cmd.ExecuteNonQuery(); conn.Close(); } } void conn_InfoMessage(object sender, SqlInfoMessageEventArgs e) { MessageBox.Show(string.Format("Source:{0},Message:{1}", e.Source, e.Message)); }
值得注意的是,不管是SQLException還是InfoMessage中的事件參數SqlInfoMessageEventArgs,它們都包含一個Errors的集合,里面包含了所有的錯誤實例。一個完善的異常處理,應該遍歷它們。例如下面這樣
public static void ShowSqlException(string connectionString) { string queryString = "EXECUTE NonExistantStoredProcedure"; StringBuilder errorMessages = new StringBuilder(); using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(queryString, connection); try { command.Connection.Open(); command.ExecuteNonQuery(); } catch (SqlException ex) { for (int i = 0; i < ex.Errors.Count; i++) { errorMessages.Append("Index #" + i + "\n" + "Message: " + ex.Errors[i].Message + "\n" + "LineNumber: " + ex.Errors[i].LineNumber + "\n" + "Source: " + ex.Errors[i].Source + "\n" + "Procedure: " + ex.Errors[i].Procedure + "\n"); } Console.WriteLine(errorMessages.ToString()); } } }