Lợi ích của việc sử dụng SET XACT_ABORT ON
trong một thủ tục được lưu trữ là gì?
Lợi ích của việc sử dụng SET XACT_ABORT ON
trong một thủ tục được lưu trữ là gì?
Câu trả lời:
SET XACT_ABORT ON
hướng dẫn SQL Server khôi phục lại toàn bộ giao dịch và hủy bỏ đợt khi xảy ra lỗi trong thời gian chạy. Nó bao gồm bạn trong các trường hợp như thời gian chờ lệnh xảy ra trên ứng dụng khách thay vì trong chính SQL Server (không được bao phủ trong XACT_ABORT OFF
cài đặt mặc định .)
Vì thời gian chờ truy vấn sẽ khiến giao dịch mở, SET XACT_ABORT ON
nên được khuyến nghị trong tất cả các quy trình được lưu trữ với các giao dịch rõ ràng (trừ khi bạn có lý do cụ thể để làm khác) vì hậu quả của một ứng dụng thực hiện công việc trên kết nối với giao dịch mở là thảm họa.
Có một cái nhìn tổng quan thực sự tuyệt vời trên Blog của Dan Guzman ,
BEGIN TRY
- BEGIN CATCH
và ROLLBACK
với BEGIN CATCH
khối trong Sql?
BEGIN TRY
- BEGIN CATCH
sẽ không bắt gặp những thứ như thời gian chờ xảy ra trên ứng dụng khách và một số lỗi SQL cũng không thể khắc phục được, khiến bạn có một giao dịch mở mà bạn không mong đợi.
Theo tôi, SET XACT_ABORT ON đã bị lỗi thời khi bổ sung BEGIN TRY / BEGIN CATCH trong SQL 2k5. Trước các khối ngoại lệ trong Transact-SQL, thực sự rất khó để xử lý lỗi và các quy trình không cân bằng đều quá phổ biến (các quy trình có @@ TRANCOUNT khác khi thoát so với mục nhập).
Với việc bổ sung xử lý ngoại lệ Transact-SQL sẽ dễ dàng hơn nhiều để viết các quy trình chính xác được đảm bảo để cân bằng chính xác các giao dịch. Chẳng hạn, tôi sử dụng mẫu này để xử lý ngoại lệ và giao dịch lồng nhau :
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
go
Nó cho phép tôi viết các thủ tục nguyên tử chỉ quay lại công việc của chính họ trong trường hợp có lỗi có thể phục hồi.
Một trong những vấn đề chính mà các thủ tục Transact-SQL phải đối mặt là độ tinh khiết của dữ liệu : đôi khi các tham số nhận được hoặc dữ liệu trong các bảng chỉ đơn giản là sai, dẫn đến lỗi khóa trùng lặp, lỗi ràng buộc tham chiếu, kiểm tra lỗi ràng buộc, v.v. Xét cho cùng, đó chính xác là vai trò của các ràng buộc này, nếu các lỗi về độ tinh khiết dữ liệu này là không thể và tất cả bị logic kinh doanh nắm bắt, các ràng buộc đó sẽ bị lỗi thời (cường điệu hóa thêm vào có hiệu lực). Nếu XACT_ABORT BẬT thì tất cả các lỗi này dẫn đến toàn bộ giao dịch bị mất, trái ngược với việc có thể mã hóa các khối ngoại lệ xử lý ngoại lệ một cách duyên dáng. Một ví dụ điển hình là cố gắng thực hiện một CHERTN và trở lại CẬP NHẬT về vi phạm PK.
Trích dẫn MSDN :
Khi SET XACT_ABORT BẬT, nếu câu lệnh Transact-SQL xuất hiện lỗi thời gian chạy, toàn bộ giao dịch bị chấm dứt và được khôi phục. Khi SET XACT_ABORT TẮT, trong một số trường hợp, chỉ có câu lệnh Transact-SQL gây ra lỗi được khôi phục và giao dịch tiếp tục xử lý.
Trong thực tế, điều này có nghĩa là một số câu lệnh có thể thất bại, khiến giao dịch 'hoàn thành một phần' và có thể không có dấu hiệu nào cho sự thất bại này đối với người gọi.
Một ví dụ đơn giản:
INSERT INTO t1 VALUES (1/0)
INSERT INTO t2 VALUES (1/1)
SELECT 'Everything is fine'
Mã này sẽ thực thi 'thành công' với XACT_ABORT OFF và sẽ chấm dứt với lỗi với XACT_ABORT ON ('INSERT INTO t2' sẽ không được thực thi và ứng dụng khách sẽ đưa ra một ngoại lệ).
Là một cách tiếp cận linh hoạt hơn, bạn có thể kiểm tra @@ ERROR sau mỗi câu lệnh (trường cũ) hoặc sử dụng các khối TRY ... CATCH (MSSQL2005 +). Cá nhân tôi thích đặt XACT_ABORT ON bất cứ khi nào không có lý do cho một số xử lý lỗi nâng cao.
Về thời gian chờ của khách hàng và việc sử dụng XACT_ABORT để xử lý chúng, theo tôi, có ít nhất một lý do rất chính đáng để có thời gian chờ trong các API khách như SqlClient và đó là để bảo vệ mã ứng dụng khách khỏi các bế tắc xảy ra trong mã máy chủ SQL. Trong trường hợp này, mã máy khách không có lỗi, nhưng phải tự bảo vệ nó khỏi bị chặn vĩnh viễn chờ lệnh hoàn thành trên máy chủ. Do đó, ngược lại, nếu thời gian chờ của máy khách phải tồn tại để bảo vệ mã máy khách, thì XACT_ABORT ON cũng phải bảo vệ mã máy chủ khỏi sự hủy bỏ của máy khách, trong trường hợp mã máy chủ mất nhiều thời gian để thực thi hơn là máy khách sẵn sàng chờ đợi.