2010-12-10 28 views
6

Tôi đã tìm thấy và bài viết trong MSDN Lbrary giải thích rằng try/catch không xử lý các lỗi được ném khi không thể tìm thấy đối tượng. SO, mặc dù tôi quấn một giao dịch trong một try/catch, cụm từ rollback sẽ không thực hiện:xử lý lỗi giao dịch khi đối tượng không tồn tại

BEGIN TRY 
BEGIN TRANSACTION 

    SELECT 1 FROM dbo.TableDoesNotExists 
    PRINT ' Should not see this' 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    ROLLBACK TRANSACTION 
    SELECT 
      ERROR_MESSAGE() 
END CATCH 

--PRINT 'Error Number before go: ' + CAST(@@Error AS VARCHAR) 

go 
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR) 
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR) 

cách khuyến khích để xử lý các lỗi ném là gì khi một đối tượng không tồn tại, đặc biệt là khi có một giao dịch liên quan đến . Tôi có nên tack mã bit này thay cho hai báo cáo in cuối cùng:

IF @@ERROR <> 0 AND @@TRANCOUNT > 0 
BEGIN 
    PRINT 'Rolling back txn' 
    ROLLBACK TRANSACTION 
END 

go 

PRINT 'Transaction Count again: ' + CAST(@@TRANCOUNT AS VARCHAR) 

Trả lời

0

Tại sao bạn cố truy xuất dữ liệu từ bảng không tồn tại?

Khối xây dựng cơ bản của cơ sở dữ liệu là một bảng. Không biết những gì trong lược đồ của bạn về bản chất là cố gắng sử dụng SQL như một ngôn ngữ động, mà nó không phải là.

Tôi sẽ suy nghĩ lại về thiết kế của bạn; mà không biết nhiều hơn về các bảng trong cơ sở dữ liệu của bạn và mục đích sử dụng của nó thì thật khó cho những người khác giúp đỡ về vấn đề này. Thêm một số thông tin khác cho câu hỏi của bạn.

EDIT Tôi đã có một chi của BOL và cách khuyến khích để xử lý các lỗi khi một đối tượng không tồn tại như sau:

Bạn có thể sử dụng try ... catch để xử lý các lỗi rằng xảy ra trong khi biên dịch hoặc biên dịch lại mức tuyên bố bằng cách thực thi mã tạo lỗi trong một lô riêng biệt trong khối TRY. Ví dụ: Ví dụ, bạn thực hiện việc này bằng cách đặt mã trong quy trình được lưu trữ hoặc bằng cách thực hiện câu lệnh Transact-SQL động bằng cách sử dụng sp_executesql. Điều này cho phép TRY ... CATCH để bắt lỗi tại mức độ thực thi cao hơn số lỗi xảy ra .

Tôi thử nghiệm này bằng cách sử dụng các thủ tục sau đây

CREATE PROCEDURE [dbo].[BrokenProcedure] 
AS 
BEGIN 
    SET NOCOUNT ON; 
    SELECT * FROM MissingTable 
END 
GO 

Sau đó gọi nó trong một khối TRY..CATCH:

BEGIN TRY 
    PRINT 'Error Number before: ' + CAST(@@Error AS VARCHAR) 
    EXECUTE [dbo].[BrokenProcedure] 
    PRINT ' Should not see this' 
END TRY 
BEGIN CATCH 
    PRINT 'Error Number in catch: ' + CAST(@@Error AS VARCHAR) 
END CATCH 

Hệ quả là đầu ra sau đây:

Error Number trước: 0

Error Number trong catch: 208

Nó không phải là một giải pháp hoàn hảo như bạn sẽ phải tạo thủ tục (hoặc sử dụng SQL động) cho tất cả các truy cập bảng của bạn, nhưng đó là phương pháp đề nghị bởi MS.

+1

Đôi khi trong môi trường năng động, bạn không biết giản đồ chính xác ; một quá trình khác có thể thay đổi cấu trúc cơ sở dữ liệu, do đó, điều cần thiết là việc xử lý ngoại lệ try/catch bình thường sẽ hoạt động như bình thường. –

+0

Điểm công bằng. Có, việc xử lý try/catch sẽ hoạt động chính xác nhưng tôi không bảo vệ MS; Tôi chỉ không đồng ý với việc sử dụng cơ sở dữ liệu này. – Tony

+0

Tony, Kịch bản này xuất hiện trong môi trường thử nghiệm và phát triển của chúng tôi, nơi chúng tôi có nhiều nhà phát triển cùng làm việc trên những thay đổi mà họ đang thực hiện. Bây giờ đây là một tình huống mà tôi không thể kiểm soát được, vì vậy tôi không thể thay đổi nó. Tuy nhiên, vì các thay đổi có thể xảy ra với các đối tượng trong thử nghiệm, tôi cần có khả năng xử lý các lỗi được tạo ra từ các đối tượng bị thiếu và tôi nghĩ cơ chế try/catch sẽ có thể xử lý được. Vì nó không phải là tôi đang cố gắng tìm ra cách tốt nhất để sử dụng các giao dịch để những thay đổi mà tôi chịu trách nhiệm không kết thúc ở một trạng thái không nhất quán nào đó. – gr928x

0

Bây giờ, bạn đã gặp phải một vấn đề thú vị (dù sao, với tôi). Bạn không nên bắt đầu một giao dịch vì lô sẽ không biên dịch. Tuy nhiên, nó có thể biên dịch và sau đó trình biên dịch cấp tuyên bố không thành công sau này.

See this question What is wrong with my Try Catch in T-SQL?

Tuy nhiên, trong hoặc trường hợp bạn có thể sử dụng SET XACT_ABORT ON. Điều này cho biết thêm khả năng dự đoán bởi vì một hiệu ứng là tự động quay trở lại bất kỳ giao dịch nào. Nó cũng ngăn chặn lỗi 266. Xem này SO question quá

SET XACT_ABORT ON 
BEGIN TRY 
    BEGIN TRANSACTION 

    SELECT 1 FROM dbo.TableDoesNotExists 
    PRINT ' Should not see this' 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    -- not needed, but looks weird without a rollback. 
    -- you could forget SET XACT_ABORT ON 
    -- Use XACT_STATE avoid double rollback errors 
    IF XACT_STATE() <> 0 
     ROLLBACK TRANSACTION 

    SELECT 
      ERROR_MESSAGE() 
END CATCH 

go 
--note, this can't be guaranteed to give anything 
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR) 
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR) 
1

Bạn có thể kiểm tra sự tồn tại của một đối tượng với object_id():

IF OBJECT_ID('MyTable') IS NULL RAISERROR('Could not find MyTable.', 18, 0) 
+1

vâng, tôi có thể nhưng điều này không thể mở rộng. Hãy tưởng tượng Nếu tôi đang triển khai một kịch bản thử nghiệm chạm vào 50 đối tượng, tôi có thử nghiệm cho từng đối tượng không? Dường như với tôi rằng thử/bắt nên xử lý các lỗi ở nơi đầu tiên. – gr928x

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