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
在此处添加新的更新。最新的MSDN更新显示了如何使用XACT_ABORT ON和TRY/CATCH块。MSDN Link
-- Check to see whether this stored procedure exists.
IF OBJECT_ID (N'usp_GetErrorInfo', N'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
GO
-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_LINE () AS ErrorLine
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_MESSAGE() AS ErrorMessage;
GO
-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- A FOREIGN KEY constraint exists on this table. This
-- statement will generate a constraint violation error.
DELETE FROM Production.Product
WHERE ProductID = 980;
-- If the DELETE statement succeeds, commit the transaction.
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Execute error retrieval routine.
EXECUTE usp_GetErrorInfo;
-- Test XACT_STATE:
-- If 1, the transaction is committable.
-- If -1, the transaction is uncommittable and should
-- be rolled back.
-- XACT_STATE = 0 means that there is no transaction and
-- a commit or rollback operation would generate an error.
-- Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N'The transaction is in an uncommittable state.' +
'Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
-- Test whether the transaction is committable.
-- You may want to commit a transaction in a catch block if you want to commit changes to statements that ran prior to the error.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N'The transaction is committable.' +
'Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH;
GO
6条答案
按热度按时间qnyhuwrf1#
SET XACT_ABORT ON
指示SQL Server在发生运行时错误时回滚整个事务并中止批处理。它适用于在客户端应用程序上而不是在SQL Server本身发生命令超时的情况(默认的XACT_ABORT OFF
设置不适用于这种情况)。由于查询超时将使事务保持打开状态,因此建议在所有具有显式事务的存储过程中使用
SET XACT_ABORT ON
(除非您有特殊的理由不这样做),因为应用程序在具有打开事务的连接上执行工作的后果是灾难性的。在Dan Guzman's Blog上有一个非常棒的概述,
nbewdwxp2#
在我看来,SQL 2k 5中添加的开始TRY/BEGIN CATCH使SET XACT_ABORT ON过时了。在Transact-SQL中出现异常块之前,处理错误确实很困难,而且不平衡的过程太常见了(与入口相比,在出口处具有不同的@@TRANCOUNT的过程)。
有了Transact-SQL异常处理的加入,编写保证正确平衡事务的正确过程就容易多了。
它允许我编写原子过程,在出现可恢复错误的情况下,只回滚自己的工作。
Transact-SQL过程面临的主要问题之一是数据纯度:有时接收到的参数或表中的数据完全是错误的,导致重复键错误、引用约束错误、检查约束错误等等。毕竟,这正是这些约束的作用,如果这些数据纯度错误不可能出现,并且都被业务逻辑捕获,这些约束都将被废弃如果XACT_ABORT为ON,则所有这些错误都将导致整个事务丢失,而不是编写异常块来优雅地处理异常。一个典型的例子是尝试执行INSERT并在PK冲突时恢复到UPDATE。
t30tvxxf3#
报价MSDN:
当SET XACT_ABORT为ON时,如果Transact-SQL语句引发运行时错误,则终止并回滚整个事务。当SET XACT_ABORT为OFF时,在某些情况下,只回滚引发错误的Transact-SQL语句,而事务继续处理。
实际上,这意味着某些语句可能会失败,使事务“部分完成”,并且调用方可能没有失败的迹象。
举个简单的例子:
XACT_ABORT为OFF时,此代码将“成功”执行,XACT_ABORT为ON时,此代码将因错误而终止(“INSERT INTO t2”将不会执行,并且客户端应用程序将引发异常)。
作为一种更灵活的方法,您可以在每个语句后检查@@ERROR(老方法),或者使用TRY... CATCH块(MSSQL 2005+)。就我个人而言,只要没有必要进行某些高级错误处理,我就更喜欢将XACT_ABORT设置为ON。
k7fdbhmy4#
关于客户端超时和使用XACT_ABORT来处理它们,在我看来,至少有一个很好的理由在SqlClient这样的客户端API中使用超时,那就是保护客户端应用程序代码不受SQL Server代码中发生的死锁的影响。在这种情况下,客户端代码没有错误,但必须保护自己不被永远阻塞,以等待服务器上的命令完成。因此,相反,如果必须存在客户端超时来保护客户端代码,那么XACT_ABORT ON也必须保护服务器代码不受客户端异常终止的影响,以防服务器代码的执行时间比客户端愿意等待的时间长。
bjp0bcyl5#
它用于事务管理,以确保任何错误都会导致事务回滚。
ippsafx76#
在此处添加新的更新。最新的MSDN更新显示了如何使用XACT_ABORT ON和TRY/CATCH块。MSDN Link