以前極其的抱怨使用存儲過程,以爲存儲過程不該該出如今如今的新項目中,html
可是最近研究存儲過程,發現存儲過程的優勢也是及其的耀眼!sql
以前只盯着存儲過程的缺點,有點一葉障目了。數據庫
前一週本身摸索着寫的存儲過程,寫的太幼稚了,不規範。sqlserver
以前在《存儲過程——C#中調用存儲過程的簡單示例》中,測試
咱們在存儲過程當中的事務中定義了一個臨時變量@sum
,在事務的每一句sql語句後都@sum+@@error
,最後根據@sum
是否爲0來判斷是否有異常,code
若是沒有異常則@@error
爲0,有異常則@@error
值爲錯誤代碼,即必定不爲0orm
因此,能夠經過最終的@sum判斷是否有異常,server
可是有一點要說明的是,@@error
對那種重大錯誤沒法捕捉,並且@@error
只對其前一句sql語句生效htm
因此,建議仍是使用TRY……CATCH對象
這裏定義一個捕獲異常的存儲過程,實現將存儲過程當中出現的異常記錄在數據庫的異常信息表中。
本示例中,所有的存儲過程都是在一個新建的測試數據庫ShanTest數據庫中進行的
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
異常信息表中字段以下:
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;
在存儲過程 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;
切記咱們在業務中須要使用存儲過程的時候,一旦使用了事務,則咱們必須在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表中添加了一條記錄: