NHIỀU không bao gồm tên của thủ tục gọi trừ khi thông báo lỗi tùy chỉnh được chỉ định


7

Tôi đang trải qua một số hành vi THROWmà tôi không thể hiểu. Hãy xem xét các thủ tục được lưu trữ sau đây:

CREATE PROCEDURE usp_division_err AS 
SET NOCOUNT ON;
BEGIN TRY
    EXEC('select 1/0')
END TRY
BEGIN CATCH
    THROW;
END CATCH 

Khi thủ tục được thực thi, lỗi sau đây được nêu ra:

Msg 8134, Cấp 16, Trạng thái 1, Dòng 1
Chia không có lỗi.

Lưu ý, không có thông tin về quy trình mà lỗi được nêu ra được bao gồm. Đó là bởi vì SQL động, sai lầm được thực thi trong một phạm vi khác và điều đó là tốt. Tuy nhiên, thay đổi CATCH-block để trông như thế này

BEGIN CATCH
    THROW 50000, 'An error occurred.', 1;
END CATCH 

và việc thực hiện thủ tục sẽ đưa ra lỗi này thay vào đó:

Msg 50000, Cấp 16, Trạng thái 1, Quy trình usp_division_err, Dòng 7 [Batch Start Line 0]
Xảy ra lỗi.

Lỗi vẫn gặp phải khi thực thi SQL động, nhưng khi tôi chỉ định thủ công số lỗi và thông báo lỗi (tham số thứ nhất và thứ hai của THROW), tên thủ tục của quy trình thực thi bằng cách nào đó sẽ xuất hiện.

Tại sao tên thủ tục xuất hiện trong thông báo lỗi thứ hai mà không phải là tên đầu tiên?


Không biết điều này có giúp ích gì không, nhưng thay đổi thành chỉ chọn 1/0 thay vì Exec ('chọn 1/0') và bạn nhận được cả hai: Msg 8134, Cấp 16, Trạng thái 1, Quy trình usp_division_err, Dòng 4 [Bắt đầu hàng loạt Dòng 10] Chia cho không có lỗi gặp phải.
Kevin3NF

2
Chà, lời giải thích duy nhất là khi bạn sử dụng cú ném mà không có gì, bạn đang chuyển hướng ngoại lệ ban đầu (mà bạn đã giải thích chính xác, vì sql động, không hiển thị bất kỳ chi tiết nào). Khi bạn sử dụng cú ném với lỗi tùy chỉnh, bạn đang ném một lỗi MỚI, do đó nó sẽ hiển thị cho bạn các chi tiết.
Renato Afonso

Tôi đã phát hiện ra rằng nhiều thiết lập EF cũng sẽ không trả lại tên SP khi chuyển lỗi xuống dấu vết ngăn xếp (không chắc nguyên nhân là gì ..), vì vậy tôi luôn sử dụng FORMATMESSAGEtrong lần ném ngoài cùng của mình để nối tên SP vào Tin nhắn với OBJECT_NAME(@@PROCID).
LowlyDBA

Câu trả lời:


2

CATCHnhư thế này:

BEGIN CATCH
    DECLARE @msg nvarchar(4000) = ERROR_MESSAGE()
    DECLARE @errno int = 50000 + ERROR_NUMBER();
    DECLARE @state int = ERROR_STATE();
    THROW @errno, @msg, @state;
END CATCH 

Điều đó cho phép bạn chuyển tất cả các tham số vào THROWcâu lệnh để nó có thể gửi lại cho người gọi.

Tôi đã thử nghiệm như thế này:

USE tempdb;
IF OBJECT_ID('dbo.usp_division_err', 'P') IS NOT NULL 
DROP PROCEDURE dbo.usp_division_err;
GO
CREATE PROCEDURE dbo.usp_division_err AS 
SET NOCOUNT ON;
BEGIN TRY
    EXEC('select 1/0');
END TRY
BEGIN CATCH
    DECLARE @msg nvarchar(4000) = ERROR_MESSAGE()
    DECLARE @errno int = 50000 + ERROR_NUMBER();
    DECLARE @state int = ERROR_STATE();
    THROW @errno, @msg, @state;
END CATCH 
GO
EXEC dbo.usp_division_err;

Kết quả:

Msg 58134, Cấp 16, Trạng thái 1, Quy trình dbo.usp_division_err, Dòng 10 [Batch Start Line 16]
Chia cho số không gặp phải lỗi.

Để có được số lỗi gốc, bạn chỉ cần trừ 50000 từ số lỗi được báo cáo. Vì các tham số cho THROWlà tùy chọn, phải có hai đường dẫn mã bên trong THROW, một đường dẫn báo cáo tên thủ tục và một đường dẫn không có. Tôi sẽ để nó cho người đọc quyết định đường dẫn mã nào thực hiện điều đó.


1
Vì vậy, cuối cùng, chúng ta cần chỉ định thủ công các tham số THWAY để có được bối cảnh (thủ tục) trong khi vẫn giữ thông báo lỗi trong cùng, số và trạng thái từ các hàm có liên quan. Tiện lợi!
kstallah
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.