SQL Server 中的異常處理
為什么我們需要 SQL Server 中的異常處理?
讓我們通過一個(gè)示例來了解 SQL Server 中異常處理的必要性。因此,創(chuàng)建一個(gè) SQL Server 存儲(chǔ)過程,通過執(zhí)行以下查詢來除以兩個(gè)數(shù)字。
IF OBJECT_ID('spDivideTwoNumber','P') IS NOT NULL
DROP PROCEDURE spDivideTwoNumber
GO
CREATE PROCEDURE spDivideTwoNumber(
@Number1 INT,
@Number2 INT
)
AS
BEGIN
DECLARE @Result INT
SET @Result = 0
SET @Result = @Number1 / @Number2
PRINT '結(jié)果是:' + CAST(@Result AS VARCHAR)
END
當(dāng)我們把0傳遞給這個(gè)存儲(chǔ)過程的第二個(gè)參數(shù)時(shí),我們會(huì)得到一個(gè)錯(cuò)誤
EXEC spDivideTwoNumber 100, 0
以下是 SQL Server Management Studio 中的輸出
消息 8134,級(jí)別 16,狀態(tài) 1,過程 spDivideTwoNumber,第 10 行
遇到以零作除數(shù)錯(cuò)誤。
結(jié)果是:0
我們可以看到,即使遇到了錯(cuò)誤,SqlServer依然會(huì)繼續(xù)執(zhí)行后面的語句,最終打印了結(jié)果是:0
所以,上述執(zhí)行的問題在于,即使程序發(fā)生錯(cuò)誤,它仍然顯示結(jié)果,因此用戶有可能感到困惑。
發(fā)生異常時(shí) SQL Server 中會(huì)發(fā)生什么?
在 SQL Server 中,每當(dāng)發(fā)生異常時(shí),它都會(huì)顯示異常消息,然后繼續(xù)執(zhí)行程序。但在 C#、Java、C++ 等編程語言中,每當(dāng)發(fā)生異常時(shí),程序執(zhí)行就會(huì)在異常發(fā)生的那一行異常終止。
在上述案例中,這種行為是錯(cuò)誤的,因?yàn)楫?dāng)編程語言中發(fā)生錯(cuò)誤時(shí),它們會(huì)直接跳過錯(cuò)誤后的所有語句的執(zhí)行,但是在 SqlServer中發(fā)生錯(cuò)誤后,執(zhí)行不會(huì)停止。例如,在上面的存儲(chǔ)過程中,當(dāng)異常發(fā)生時(shí),它仍然顯示不應(yīng)該發(fā)生的 “結(jié)果是:0”。
SQL Server 中的異常處理是什么?
隨著 SQL Server 2005 中引入 Try/Catch 塊,SQL Server 中的錯(cuò)誤處理現(xiàn)在與 C# 和 Java 等編程語言非常相似。但是,在了解使用 try/catch 塊進(jìn)行錯(cuò)誤處理之前,讓我們退后一步,了解在 2005 年之前的 SQL Server 中如何使用系統(tǒng)函數(shù) RAISERROR 和 @@Error 進(jìn)行錯(cuò)誤處理。
在 SQL Server 中使用 RAISERROR 系統(tǒng)函數(shù)處理異常
讓我們更改我們?cè)谏弦粋€(gè)示例中創(chuàng)建的相同存儲(chǔ)過程,如下所示,以使用 Raiseerror 系統(tǒng)函數(shù)來處理 SQL Server 中的異常。
IF OBJECT_ID('spDivideTwoNumber','P') IS NOT NULL
DROP PROCEDURE spDivideTwoNumber
GO
CREATE PROCEDURE spDivideTwoNumber(
@Number1 INT,
@Number2 INT
)
AS
BEGIN
DECLARE @Result INT
SET @Result = 0
IF(@Number2 = 0)
BEGIN
RAISERROR('第二個(gè)數(shù)字不能為0', 16, 1)
END
ELSE
BEGIN
SET @Result = @Number1 / @Number2
PRINT '結(jié)果是: ' + CAST(@Result AS VARCHAR)
END
END
當(dāng)我們?cè)俅螆?zhí)行以下語句時(shí)
EXEC spDivideTwoNumber 100, 0
以下是 SQL Server Management Studio 中的輸出
消息 50000,級(jí)別 16,狀態(tài) 1,過程 spDivideTwoNumber,第 11 行
第二個(gè)數(shù)字不能為0
在上述過程中,如果第二個(gè)數(shù)字為零,我們使用系統(tǒng)定義的 Raiserror () 函數(shù)將錯(cuò)誤消息返回給調(diào)用應(yīng)用程序。
SQL Server 中的 RaiseError 系統(tǒng)函數(shù)是什么?
SQL Server 中的 RaiseError 系統(tǒng)定義函數(shù)采用 3 個(gè)參數(shù),如下所示。
RAISERROR('錯(cuò)誤消息', ErrorSeverity, ErrorState)
- 錯(cuò)誤消息 :您希望在引發(fā)異常時(shí)顯示的自定義錯(cuò)誤消息。
- 錯(cuò)誤嚴(yán)重性 :當(dāng)我們?cè)?SQL Server 中返回任何自定義錯(cuò)誤時(shí),我們需要將 ErrorSeverity 級(jí)別設(shè)置為 16,這表明這是一個(gè)一般錯(cuò)誤,并且該錯(cuò)誤可以由用戶更正。在我們的示例中,用戶可以通過為第二個(gè)參數(shù)提供非零值來糾正錯(cuò)誤。
- 錯(cuò)誤狀態(tài) : ErrorState 也是 1 到 255 之間的整數(shù)值。如果您將錯(cuò)誤狀態(tài)值設(shè)置在 1 到 127 之間,RAISERROR() 函數(shù)只能生成自定義錯(cuò)誤。
SQL Server 中的@@Error 系統(tǒng)函數(shù)
在 SQL Server 2000 中,為了檢測(cè)錯(cuò)誤,我們使用了@@Error 系統(tǒng)函數(shù)。如果有錯(cuò)誤,@@Error 系統(tǒng)函數(shù)返回一個(gè) NON-ZERO 值,否則,ZERO表示前面的SQL語句執(zhí)行沒有任何錯(cuò)誤。讓我們修改存儲(chǔ)過程以使用@@ERROR系統(tǒng)函數(shù),如下所示。
ALTER PROCEDURE spDivideTwoNumber(
@Number1 INT,
@Number2 INT
)
AS
BEGIN
DECLARE @Result INT
SET @Result = 0
IF(@Number2 = 0)
BEGIN
RAISERROR('第二個(gè)數(shù)字不能為0',16,1)
END
ELSE
BEGIN
SET @Result = @Number1 / @Number2
END
IF(@@ERROR <> 0)
BEGIN
PRINT '發(fā)生了錯(cuò)誤'
END
ELSE
BEGIN
PRINT '結(jié)果是:' + CAST(@Result AS VARCHAR)
END
END
當(dāng)我們?cè)俅螆?zhí)行以下語句時(shí)
EXEC spDivideTwoNumber 100, 0
以下是 SQL Server Management Studio 中的輸出
消息 50000,級(jí)別 16,狀態(tài) 1,過程 spDivideTwoNumber,第 11 行
第二個(gè)數(shù)字不能為0
發(fā)生了錯(cuò)誤
SQL Server 中的預(yù)定義錯(cuò)誤術(shù)語
每當(dāng)在程序中發(fā)生錯(cuò)誤,例如將數(shù)字除以零、違反主鍵、違反檢查約束等,系統(tǒng)都會(huì)顯示一條錯(cuò)誤消息,告訴我們代碼中遇到的問題。程序中發(fā)生的每個(gè)錯(cuò)誤都與四個(gè)屬性相關(guān)聯(lián)。
- 錯(cuò)誤編號(hào)
- 錯(cuò)誤信息
- 嚴(yán)重程度
- 錯(cuò)誤狀態(tài)
比如:
消息 8134(錯(cuò)誤編號(hào)),級(jí)別 16(嚴(yán)重級(jí)別),狀態(tài) 1(狀態(tài)),遇到除以零錯(cuò)誤(錯(cuò)誤消息)
-
錯(cuò)誤編號(hào) 是為 SQL Server 中發(fā)生的每個(gè)錯(cuò)誤提供的唯一標(biāo)識(shí)符。對(duì)于預(yù)定義的錯(cuò)誤,該值將低于 50,000,對(duì)于用戶定義的錯(cuò)誤,該值必須高于或等于 50,000。在引發(fā)自定義錯(cuò)誤時(shí),如果我們不指定錯(cuò)誤編號(hào),則默認(rèn)情況下會(huì)將錯(cuò)誤編號(hào)設(shè)置為 50000。
-
錯(cuò)誤信息 是描述發(fā)生的錯(cuò)誤的簡(jiǎn)短信息,最多 2047 個(gè)字符。
-
嚴(yán)重程度 這說明錯(cuò)誤的重要性,范圍在 0 到 24 之間。其中
- 0 到 9:不是服務(wù),可被視為信息或狀態(tài)消息。
- 11 到 16: 表示這些錯(cuò)誤可以由用戶創(chuàng)建。
- 17 到 19:表示這些是用戶無法糾正的軟件錯(cuò)誤,必須向系統(tǒng)管理員報(bào)告。
- 20 到 24:表示致命錯(cuò)誤,如果發(fā)生這些錯(cuò)誤,可能會(huì)損壞系統(tǒng)或數(shù)據(jù)庫。所以這里的連接立即與數(shù)據(jù)庫終止。
-
錯(cuò)誤狀態(tài) 它是一個(gè)不那么重要的任意值,可以在 0 到 127 之間。每當(dāng)必須在多個(gè)地方發(fā)生相同的錯(cuò)誤時(shí),我們都會(huì)使用它。
注意:我們可以在“系統(tǒng)消息”表下找到所有預(yù)定義錯(cuò)誤的信息
比如:
select * from sys.messages where language_id = 2052 and message_id = 8134
輸出如下:
| message_id | language_id | severity | is_event_logged | text |
|---|---|---|---|---|
| 8134 | 2052 | 16 | 0 | 遇到以零作除數(shù)錯(cuò)誤。 |

浙公網(wǎng)安備 33010602011771號(hào)