2009-04-07 79 views
27

Chúng tôi có một ứng dụng lớn chủ yếu được viết trong SQL Server 7.0, nơi tất cả các cuộc gọi cơ sở dữ liệu được lưu trữ thủ tục. Chúng tôi hiện đang chạy SQL Server 2005, cung cấp nhiều tính năng T-SQL hơn.Cách xử lý lỗi SQL Server T-SQL thực tiễn tốt nhất là gì?

Sau mỗi lần SELECT, INSERT, UPDATE và DELETE, @@ ROWCOUNT và @@ ERROR bị bắt vào biến cục bộ và được đánh giá cho các sự cố. Nếu có một vấn đề sau đây được thực hiện:

  • lỗi thông số đầu ra thông điệp được thiết lập
  • rollback (nếu cần thiết) được thực hiện
  • thông tin được viết (INSERT) để đăng nhập bảng
  • trở lại với một số lỗi, duy nhất cho quy trình này (dương tính nếu gây tử vong, âm tính là cảnh báo)

Tất cả đều không kiểm tra các hàng (chỉ khi nó được biết) và một số khác biệt với ít hoặc nhiều thông tin nhật ký/gỡ lỗi. Ngoài ra, logic hàng đôi khi được tách ra khỏi logic lỗi (trên các cập nhật trong đó một trường đồng thời được kiểm tra trong mệnh đề WHERE, các hàng = 0 có nghĩa là ai đó đã cập nhật dữ liệu). Tuy nhiên, đây là ví dụ khá chung chung:

SELECT, INSERT, UPDATE, or DELETE 

SELECT @[email protected]@ERROR, @[email protected]@ROWCOUNT 
IF @Rows!=1 OR @Error!=0 
BEGIN 
    SET @ErrorMsg='ERROR 20, ' + ISNULL(OBJECT_NAME(@@PROCID), 'unknown') 
           + ' - unable to ???????? the ????.' 
    IF @@TRANCOUNT >0 
    BEGIN 
     ROLLBACK 
    END 

    SET @LogInfo=ISNULL(@LogInfo,'')+'; '+ISNULL(@ErrorMsg,'')+ 
     + ' @YYYYY='  +dbo.FormatString(@YYYYY) 
     +', @XXXXX='  +dbo.FormatString(@XXXXX) 
     +', Error='   +dbo.FormatString(@Error) 
     +', Rows='   +dbo.FormatString(@Rows) 

    INSERT INTO MyLogTable (...,Message) VALUES (....,@LogInfo) 

    RETURN 20 

END 

Tôi đang tìm cách thay thế cách chúng tôi thực hiện điều này bằng T-SQL TRY-CATCH. Tôi đã đọc về cú pháp TRY...CATCH (Transact-SQL), do đó, không chỉ đăng một số tóm tắt về điều đó. Tôi đang tìm bất kỳ ý tưởng hay nào và cách tốt nhất để thực hiện hoặc cải thiện các phương pháp xử lý lỗi của chúng tôi. Nó không phải là Try-Catch, chỉ là bất kỳ việc sử dụng xử lý lỗi T-SQL nào tốt hay tốt nhất.

Trả lời

29

Bạn nên đọc này:

http://www.sommarskog.se/error-handling-I.html

Tôi không thể khuyên liên kết đủ cao. Đó là một chút dài, nhưng trong một cách tốt.

Có tuyên bố từ chối trách nhiệm ở phía trước rằng ban đầu nó được viết cho SQL Server 2000, nhưng nó cũng bao gồm khả năng xử lý lỗi try/catch mới trong SQL Server 2005+.

+0

Tôi cảm thấy nó bỏ qua trên các công cụ SQL Server 2005, nhưng tuyệt vời anyway. Và phần còn lại của trang web của anh ấy. – gbn

+0

Đối với SQL Server 2005+, hãy bắt đầu tại đây http://www.sommarskog.se/error_handling/Part1.html –

3

Dường như bạn đã xử lý rất tốt điều này rồi. Tôi nghi ngờ bạn đang làm hơn 95% các lập trình viên SQL trên mạng.

Bạn nên tìm một số thông tin thú vị ở đây:

Một đề xuất [không liên quan]: bắt đầu sử dụng '<>' thay vì '! ='.

[* SQL Junkies đã biến mất, vì vậy bài viết thứ hai không khả dụng. Tôi sẽ cố gắng làm cho nó được tái bản ở đâu đó và cập nhật liên kết.]

+0

tại sao lại sử dụng '<>' thay vì '! ='? –

+1

Đặc tả ANSI chỉ định <>. Nhiều db cũng hỗ trợ! =, Nhưng nó không phải là tiêu chuẩn. –

+0

http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt Xem phần 5.2 –

6

Không có tập hợp các phương pháp hay nhất về đá để xử lý lỗi. Tất cả đều đi xuống theo nhu cầu của bạn và nhất quán.

Đây là mẫu của bảng và thủ tục lưu trữ lưu trữ số điện thoại.

SET ANSI_NULLS ON 
    GO 
    SET QUOTED_IDENTIFIER ON 
    GO 
    SET ANSI_PADDING ON 
    GO 
    CREATE TABLE [dbo].[Phone](
     [ID] [int] IDENTITY(1,1) NOT NULL, 
     [Phone_Type_ID] [int] NOT NULL, 
     [Area_Code] [char](3) NOT NULL, 
     [Exchange] [char](3) NOT NULL, 
     [Number] [char](4) NOT NULL, 
     [Extension] [varchar](6) NULL, 
    CONSTRAINT [PK_Phone] PRIMARY KEY CLUSTERED 
    (
     [ID] 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 
    SET ANSI_PADDING OFF 
    GO 
    /**/ 

    CREATE PROCEDURE [dbo].[usp_Phone_INS] 
     @Customer_ID INT 
     ,@Phone_Type_ID INT 
     ,@Area_Code CHAR(3) 
     ,@Exchange CHAR(3) 
     ,@Number CHAR(4) 
     ,@Extension VARCHAR(6) 
    AS 
    BEGIN 
     SET NOCOUNT ON; 

     DECLARE @Err INT, @Phone_ID INT 

     BEGIN TRY 
      INSERT INTO Phone 
       (Phone_Type_ID, Area_Code, Exchange, Number, Extension) 
      VALUES 
       (@Phone_Type_ID, @Area_Code, @Exchange, @Number, @Extension) 
      SET @Err = @@ERROR 
      SET @Phone_ID = SCOPE_IDENTITY() 
      /* 
       Custom error handling expected by the application. 
       If Err = 0 then its good or no error, if its -1 or something else then something bad happened. 
      */ 
      SELECT ISNULL(@Err,-1) AS Err, @Phone_ID 
     END TRY 
     BEGIN CATCH 
      IF (XACT_STATE() <> 0) 
       BEGIN 
        ROLLBACK TRANSACTION 
       END 

      /* 
       Add your own custom error handling here to return the passed in paramters. 
       I have removed my custom error halding code that deals with returning the passed in parameter values. 
      */ 

      SELECT ERROR_NUMBER() AS Err, ISNULL(@Phone_ID,-1) AS ID 
     END CATCH 
    END 
17

Chúng tôi hiện đang sử dụng biểu mẫu này cho bất cứ thắc mắc mà chúng ta thực hiện (bạn có thể bỏ qua những thứ giao dịch, nếu bạn không cần nó trong ví dụ một lệnh DDL):

BEGIN TRANSACTION 
BEGIN TRY 
    // do your SQL statements here 

    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber, 
     ERROR_SEVERITY() AS ErrorSeverity, 
     ERROR_STATE() AS ErrorState, 
     ERROR_PROCEDURE() AS ErrorProcedure, 
     ERROR_LINE() AS ErrorLine, 
     ERROR_MESSAGE() AS ErrorMessage 

    ROLLBACK TRANSACTION 
END CATCH 

Dĩ nhiên , bạn có thể dễ dàng chèn ngoại lệ đã bắt vào bảng nhật ký lỗi của mình.

Nó hoạt động thực sự tốt cho chúng tôi. Bạn có thể thậm chí có thể tự động hóa một số chuyển đổi từ procs được lưu trữ cũ sang định dạng mới bằng cách sử dụng Code Generation (ví dụ: CodeSmith) hoặc một số mã C# tùy chỉnh.

+10

Tại sao bắt đầu giao dịch bên ngoài khối TRY, có lợi thế không? Tất cả các ví dụ trên MSDN hiển thị BEGIN TRAN là câu lệnh đầu tiên bên trong TRY http://technet.microsoft.com/en-us/library/ms179296%28v=sql.105%29.aspx – Davos

+2

XACT_STATE cũng nên được xem xét nếu sử dụng giao dịch: https://msdn.microsoft.com/en-us/library/ms189797.aspx –

Các vấn đề liên quan