存儲過程——異常捕獲&打印異常信息

shanzm-2020年5月13日

0. 背景說明

以前極其的抱怨使用存儲過程,以爲存儲過程不該該出如今如今的新項目中,html

可是最近研究存儲過程,發現存儲過程的優勢也是及其的耀眼!sql

以前只盯着存儲過程的缺點,有點一葉障目了。數據庫

前一週本身摸索着寫的存儲過程,寫的太幼稚了,不規範。sqlserver

以前在《存儲過程——C#中調用存儲過程的簡單示例》中,測試

咱們在存儲過程當中的事務中定義了一個臨時變量@sum,在事務的每一句sql語句後都@sum+@@error,最後根據@sum是否爲0來判斷是否有異常,code

若是沒有異常則@@error爲0,有異常則@@error值爲錯誤代碼,即必定不爲0orm

因此,能夠經過最終的@sum判斷是否有異常,server

可是有一點要說明的是,@@error對那種重大錯誤沒法捕捉,並且@@error只對其前一句sql語句生效htm

因此,建議仍是使用TRY……CATCH對象

這裏定義一個捕獲異常的存儲過程,實現將存儲過程當中出現的異常記錄在數據庫的異常信息表中。

本示例中,所有的存儲過程都是在一個新建的測試數據庫ShanTest數據庫中進行的



1. 創建異常信息表ErrorLog

USE [ShanTest]
GO
/****** Object:  Table [dbo].[ErrorLog]    Script Date: 2020-05-11 14:49:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ErrorLog](
	[ErrorLogID] [int] IDENTITY(1,1) NOT NULL,--異常表ID
	[ErrorTime] [datetime] NOT NULL CONSTRAINT [DF_ErrorLog_ErrorTime]  DEFAULT (getdate()),--異常時間,提供默認值就是當前時間
	[UserName] [sysname] NOT NULL,          --異經常使用戶名,這裏就是dbo,dbo是每一個數據庫的默認用戶,具備全部者權限,全稱:datebaseOwner
	[ErrorNumber] [int] NOT NULL,           --異常代碼
	[ErrorSeverity] [int] NULL,             --異常嚴重性
	[ErrorState] [int] NULL,                --異常狀態碼
	[ErrorProcedure] [nvarchar](126) NULL,  --拋異常的存儲過程
	[ErrorLine] [int] NULL,                 --錯誤行數
	[ErrorMessage] [nvarchar](4000) NOT NULL,--完整的異常信息
 CONSTRAINT [PK_ErrorLog_ErrorLogID] PRIMARY KEY CLUSTERED 
(
	[ErrorLogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

異常信息表中字段以下:
異常表字段



2. 創建保存異常信息的存儲過程

USE [ShanTest]
GO
/****** Object:  StoredProcedure [dbo].[pro_ErrorLog]    Script Date: 2020-05-11 14:15:46 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =================================================
-- Author:		shanzm
-- Create date: 2020年5月11日 
-- Description:	保存存儲過程當中捕獲的異常到ErrorLog表
-- =================================================
CREATE PROCEDURE [dbo].[pro_ErrorLog]
@ErrorLogID [int] = 0 OUTPUT 
AS                               
BEGIN
    SET NOCOUNT ON;

        INSERT [dbo].[ErrorLog]
            (
            [UserName],
            [ErrorNumber],
            [ErrorSeverity],
            [ErrorState],
            [ErrorProcedure],
            [ErrorLine],
            [ErrorMessage]
            )
        VALUES
            (
            CONVERT(sysname, CURRENT_USER),--current_user ,這裏值是dbo,dbo是每一個數據庫的默認用戶,具備全部者權限
										   --sysname類型 用於表列、變量以及用於存儲對象名的存儲過程參數,等價與nvachart(120)
            ERROR_NUMBER(),                 --錯誤代號,有不少錯誤代號,能夠自行百度
            ERROR_SEVERITY(),               --錯誤的嚴重性
            ERROR_STATE(),                  --錯誤的狀態碼
            ERROR_PROCEDURE(),              --錯誤的存儲過程
            ERROR_LINE(),                   --錯誤行號
            ERROR_MESSAGE()                 --錯誤信息
            );
        SET @ErrorLogID = @@IDENTITY;--@@IDENTITY 是插入記錄時自動產生的ID
		execute dbo.pro_PrintError;--改存儲過程會將ERROR_MESSAGE()在sql server信息窗口打印出來
END;


3. 創建在SQL Server中打印異常信息的存儲過程

在存儲過程 pro_ErrorLog 中存儲異常信息後,在調用這個存儲過程

USE [ShanTest]
GO
/****** Object:  StoredProcedure [dbo].[pro_PrintError]    Script Date: 2020-05-11 14:43:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		shanzm
-- Create date: 2020年5月11日 
-- Description:	在消息框中打印異常信息
-- =============================================
CREATE PROCEDURE [dbo].[pro_PrintError]
AS
BEGIN
    SET NOCOUNT ON;

    -- Print error information.
    PRINT 'ErrorNumber : ' +CONVERT(varchar(50), ERROR_NUMBER()) 
    PRINT 'ErrorSeverity : ' + CONVERT(varchar(5), ERROR_SEVERITY()) 
    PRINT 'ErrorState :' + CONVERT(varchar(5), ERROR_STATE()) 
    PRINT 'ErrorProcedure :' + ISNULL(ERROR_PROCEDURE(), '-') 
    PRINT 'ErrorLine :' + CONVERT(varchar(5), ERROR_LINE());
    PRINT 'ErrorMessage :' + ERROR_MESSAGE();
END;


4. 創建一個用於測試的存儲過程拋出異常進行測試

切記咱們在業務中須要使用存儲過程的時候,一旦使用了事務,則咱們必須在BEGIN CATCH語句中判斷是否有異常拋出,一旦有異常拋出,則存儲過程當中的事務必定要進行ROLLBACK

USE [ShanTest]
GO
/****** Object:  StoredProcedure [dbo].[TestErrorLog]    Script Date: 2020-05-11 15:14:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		shanzm
-- Create date: 2020年5月11日
-- Description:	用於拋出異常測試ErrorLog是否可用
-- =============================================
ALTER PROCEDURE [dbo].[TestErrorLog]   
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY---------開始捕捉異常
        BEGIN TRANSACTION------------------開始事務
		update  ShanTest.dbo.Product set Name=NULL where Id=1--這裏隨便建一個數據庫,建一個表,給該表中不容許爲空的列插入一個NUll
		--select 1/0;
        COMMIT TRAN -----------------------提交事務
    END TRY-----------結束捕捉異常

    BEGIN CATCH------有異常被捕獲
        IF @@TRANCOUNT > 0---------------------判斷有沒有事務
        BEGIN
            ROLLBACK TRAN----------------------回滾事務
        END
        EXEC pro_ErrorLog----------------------執行存儲過程將錯誤信息記錄在表當中
    END CATCH--------結束異常處理
END

執行改存儲過程,進行測試:

USE [ShanTest]
GO
EXEC [dbo].[TestErrorLog]
GO

測試結果:
SQL Serve消息框中現實消息:

ErrorNumber : 515
ErrorSeverity : 16
ErrorState :2
ErrorProcedure :TestErrorLog
ErrorLine :13
ErrorMessage :不能將值 NULL 插入列 'Name',表 'ShanTest.dbo.Product';列不容許有 Null 值。UPDATE 失敗。

該消息是由pro_PrintError存儲過程打印的
執行測試

同時ErrorLog表中添加了一條記錄:
異常表中信息



5. 參考信息

博客園:SQLServer異常捕獲
博客園:sqlserver 存儲過程 try catch TRANSACTION

相關文章
相關標籤/搜索