我在我的sp中有一个try catch块,在try中只有一个insert语句。如果是pk违规则捕获检查错误代码,如果是则更新。但有时我得到“当前事务无法提交,不能支持写入日志文件的操作。回滚事务。
在批处理结束时检测到不可提交的事务。事务被回滚。“所以我添加了xact_abort,但后来我继续得到”EXECUTE后的事务计数表示BEGIN和COMMIT语句的数量不匹配。“我找到了这个.http://www.ashishsheth.com/post/2009/08/14/Set-XACT_ABORT-ON-and-TryCatch-block-in-Sql-Server-2005.aspx
如果这是真的。如果我的try块中有xact_abort错误,我的catch代码是否会运行?
至少在SQL SERVER 2008中,SET XACT_ABORT ON会导致错误跳过CATCH块,这是不对的:
这是我尝试使用Northwind数据库的代码
SET XACT_ABORT OFF
BEGIN TRY
SELECT 1, @@TRANCOUNT
BEGIN TRAN
UPDATE [dbo].[Categories]
SET Description='BLAH'
WHERE [CategoryID]=2
SELECT 2, @@TRANCOUNT
SELECT 1/0 as whoops
COMMIT
SELECT 3, @@TRANCOUNT
END TRY
BEGIN CATCH
SELECT 'In Catch. Error occured', 4, @@TRANCOUNT
IF (XACT_STATE()) = 0
BEGIN
SELECT
N'There is no transaction'
END;
IF (XACT_STATE()) = -1
BEGIN
SELECT
N'The transaction is in an uncommittable state.' +
'Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
-- Test whether the transaction is committable.
IF (XACT_STATE()) = 1
BEGIN
SELECT
N'The transaction is committable.' +
'Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH
显然,这会在遇到SELECT 1/0语句时强制出错。使用SET XACT_ABORT OFF时,当到达CATCH块时,XACT_STATE()函数返回的值为1,导致代码运行COMMENT事务。当SET XACT_ABORT打开时,CATCH块中返回的值为-1,因此执行ROLL返回事务的代码。
这基于:
让我补充一点,在那个特定场景中(尝试插入,如果PK违规然后捕获并更新),最好使用IF EXISTS(select ....)来查看行是否存在并将UPDATE语句放在那里。将INSERT语句放在ELSE块中。更清洁。