Phương pháp tốt nhất để thêm xử lý lỗi trong các procs lưu trữ SQL 2005 là gì?


11

Cách tốt để làm cho các procs được lưu trữ đủ mạnh để chúng có thể mở rộng rất tốt và cũng có thể xử lý lỗi?

Ngoài ra, cách tốt nhất để xử lý nhiều tình huống lỗi trong một Proc được lưu trữ và có một hệ thống phản hồi thông minh sẽ trả về thông tin lỗi có ý nghĩa cho các ứng dụng gọi điện?


2
Hãy thử sử dụng khối TRY CATCH mới hơn trong SQL Server 2005. sommarskog.se/error_handling_2005.html
Sankar Reddy

Xin chào @Kacalacco ~ Tôi muốn giới thiệu trong tương lai để tự hỏi từng câu hỏi và theo cách đó chúng ta có thể có câu trả lời cụ thể tập trung vào một câu hỏi tại một thời điểm. Tôi khuyến khích bạn làm điều đó với câu hỏi này.
jcolebrand

Câu trả lời:


12

Alex Kuznetsov có một chương tuyệt vời trong cuốn sách Lập trình cơ sở dữ liệu phòng thủ (Chương 8) bao gồm các cài đặt T-SQL TRY ... CATCH, giao dịch T-SQL & SET XACT_ABORT và sử dụng xử lý lỗi phía máy khách. Nó sẽ giúp bạn rất nhiều trong việc quyết định lựa chọn nào có ý nghĩa nhất cho những gì bạn cần phải hoàn thành.

Nó có sẵn miễn phí tại trang web này . Tôi không có cách nào liên kết với công ty, nhưng tôi sở hữu phiên bản sao chép cứng của cuốn sách đó.

Có rất nhiều chi tiết nhỏ về chủ đề này được Alex giải thích rất rõ.

Theo yêu cầu của Nick ... (nhưng không phải tất cả những điều này đều có trong chương này)

Về quy mô, bạn cần trung thực một cách thô bạo về những hoạt động nào cần có trong mã db và hoạt động nào phải có trong ứng dụng. Bạn có bao giờ nhận thấy làm thế nào mã thực thi nhanh có xu hướng quay trở lại thiết kế cho một mối quan tâm duy nhất cho mỗi phương thức?

Cách dễ nhất để giao tiếp là mã lỗi tùy chỉnh (> 50.000). Nó cũng khá nhanh. Điều đó có nghĩa là bạn phải giữ đồng bộ mã db và mã ứng dụng. Với mã lỗi tùy chỉnh, bạn cũng có thể trả về thông tin hữu ích trong chuỗi thông báo lỗi. Vì bạn có mã lỗi nghiêm ngặt cho tình huống đó, bạn có thể viết trình phân tích cú pháp trong mã ứng dụng được điều chỉnh theo định dạng dữ liệu của lỗi.

Ngoài ra, những điều kiện lỗi cần thử lại logic trong cơ sở dữ liệu? Nếu bạn muốn thử lại sau X giây, thì tốt hơn hết bạn nên xử lý trong mã ứng dụng để giao dịch không bị chặn nhiều như vậy. Nếu bạn chỉ gửi lại một hoạt động DML ngay lập tức, việc lặp lại nó trong SP có thể hiệu quả hơn. Tuy nhiên, hãy nhớ rằng bạn sẽ phải sao chép mã hoặc thêm một lớp SP để thực hiện thử lại.

Thực sự, đó là nỗi đau lớn nhất với TRY ... logic CATCH trong SQL Server tại thời điểm này. Nó có thể được thực hiện, nhưng đó là một chút của một oaf. Tìm kiếm một số cải tiến đến với điều này trong SQL Server 2012, đặc biệt là ném lại các ngoại lệ của hệ thống (giữ nguyên số lỗi ban đầu). Ngoài ra, có FORMATMESSAGE , bổ sung một số tính linh hoạt trong việc xây dựng các thông báo lỗi, đặc biệt là cho mục đích ghi nhật ký.


Lời khuyên tuyệt vời và một cuốn sách rất tốt!
Mary

Red Gate cung cấp một số sách điện tử miễn phí cực kỳ hữu ích, và đây chắc chắn là một trong những cuốn sách hay hơn. Đề nghị tuyệt vời.
Matt M

Không phải tất cả các cuốn sách của họ đều làm được điều này, nhưng phiên bản miễn phí của cuốn sách "Phòng thủ ..." của Kuznetsov không chứa 2 chương cuối về Cấp độ cách ly giao dịch và Phát triển sửa đổi tồn tại đồng thời. Cho tôi. nội dung trong đó có giá trị mua.
Phil Helmer

7

Đây là mẫu của chúng tôi (đã xóa lỗi đăng nhập)

Ghi chú:

  • Nếu không có XACT_ABORT, tất cả TXN bắt đầu và cam kết / rollback phải được ghép nối
  • Cam kết giảm @@ TRANCOUNT
  • Một rollback trả về @@ TRANCOUNT về 0 nên bạn sẽ gặp lỗi 266
  • Bạn không thể ROLLBACK lớp hiện tại (ví dụ: decrement @@ TRANCOUNT khi quay lại)
  • XACT_ABORT ngăn chặn lỗi 266
  • Mỗi Proc được lưu trữ phải tuân theo cùng một khuôn mẫu để mỗi cuộc gọi là nguyên tử
  • Kiểm tra rollback thực sự là dư thừa vì XACT_ABORT. Tuy nhiên, nó làm cho tôi cảm thấy tốt hơn, trông kỳ quặc mà không có, và cho phép các tình huống mà bạn không muốn nó
  • Điều này cho phép TXN phía máy khách (như LINQ)
  • Remus Rusanulớp vỏ tương tự sử dụng điểm lưu. Tôi thích một cuộc gọi DB nguyên tử và không sử dụng các cập nhật một phần như bài viết của họ

... vì vậy đừng tạo nhiều TXN hơn bạn cần

Tuy nhiên,

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

Nếu @@ TRANCOUNT lớn hơn 0 thì sao? bạn không làm gì hay có phản hồi gì?
kacalacco

@kacalacco: không có giao dịch lồng nhau, vì vậy chúng tôi không bắt đầu một scribd.com/doc/49579859/33/Nested-Transilities-Are-Real
gbn

3

Tôi sử dụng Thử / Bắt, nhưng tôi cũng thu thập càng nhiều thông tin càng tốt và viết nó vào một lỗi bị khóa SAU khi quay lại. Trong ví dụ này, "LogEvent" là một thủ tục được lưu trữ ghi vào bảng EventLog, chứa các chi tiết về những gì đã xảy ra. GetErrorInfo () là một lệnh gọi hàm trả về thông báo lỗi chính xác.

Khi xảy ra lỗi, thông tin được thu thập, quy trình bỏ qua phần xử lý lỗi và đưa ra một bản rollback. Thông tin được ghi vào nhật ký, sau đó thủ tục thoát.

Xem xét các cuộc gọi thủ tục / chức năng bổ sung có liên quan, có vẻ như một chút trên đầu trang. TUY NHIÊN phương pháp này rất hữu ích khi cố gắng gỡ lỗi.

thực hiện LogEvent @Process, @Database, 'Cố gắng chèn blah blah blah'
BẮT ĐẦU THỬ
  chèn vào MyTable
  chọn giá trị
    từ MyOtherTable

  chọn @rowcount = @@ ROWCOUNT
KẾT THÚC
- Xử lý lỗi
BẮT ĐẦU CATCH
  chọn @error = ERROR_NUMBER (),
         @rowcount = -1,
         @TableAction = 'chèn',
         @TableName = @Database + '.MyTable',
         @AdditableInfo = '(Cố gắng chèn blah blah blah)' + dbo.GetErrorInfo ()
   Bảng GOTOAccessError
KẾT THÚC

.
.
.
.

TableAccessError:
NẾU (@@ TRANCOUNT> 0) ROLLBACK
chọn @output = trên (@TableAction) + 
       'LRI - Đã xảy ra lỗi trong khi' + 
       trường hợp (@TableAction)
         khi 'cập nhật' rồi 'cập nhật'
         khi 'xóa' rồi 'xóa'
         khác @TableAction + 'ing'
       kết thúc + 
       'hồ sơ' + 
       trường hợp (@TableAction) 
         khi 'chọn' rồi 'từ' 
         khi 'cập nhật' rồi 'vào' 
         khi 'chèn' rồi 'vào'
         khác 'từ'   
         kết thúc + 
         bảng '+ @TableName +'. '
chọn @output = @output + '@@ ERROR:' + convert (varchar (8), @ error) 
chọn @output = @output + '@@ ROWCOUNT:' + convert (varchar (8), @ rowcount) 

chọn @output = @output + isnull (@AdditableInfo, '')
thực thi LogEvent @Process, @Database, @Output
RAISERROR (@ đầu ra, 16,1) với nhật ký
chọn @ReturnCode = -1
GOTO THE_EXIT


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.