以下是外部和嵌套过程的代码
ALTER PROCEDURE dbo.NestedProcedure
AS
BEGIN
SET XACT_ABORT OFF
SET NOCOUNT ON
BEGIN TRY
DECLARE @trancount INT
SET @trancount = @@TRANCOUNT
IF @trancount = 0
BEGIN TRANSACTION
ELSE
SAVE TRANSACTION NestedProcedure
ALTER TABLE dbo.Table_2
ALTER COLUMN Column3 VARCHAR
IF @trancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT XACT_STATE()
DECLARE @error INT, @message VARCHAR(4000), @xstate INT;
SELECT @error = ERROR_NUMBER(), @message = ERROR_MESSAGE();
IF XACT_STATE() = -1
BEGIN
ROLLBACK
END
IF XACT_STATE() = 1 AND @trancount = 0
BEGIN
ROLLBACK
END
IF XACT_STATE() = 1 AND @trancount > 0
BEGIN
ROLLBACK TRANSACTION NestedProcedure
END
RAISERROR ('NestedProcedure: %d: %s', 16, 1, @error, @message)
END CATCH
END
ALTER PROCEDURE dbo.OuterProcedure
AS
BEGIN
SET XACT_ABORT OFF
SET NOCOUNT ON
BEGIN TRY
DECLARE @trancount INT
SET @trancount = @@TRANCOUNT
IF @trancount = 0
BEGIN TRANSACTION
ELSE
SAVE TRANSACTION OuterProcedure
EXEC dbo.NestedProcedure
SELECT * FROM dbo.Table_2
IF @trancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT XACT_STATE()
DECLARE @error INT, @message VARCHAR(4000), @xstate INT;
SELECT @error = ERROR_NUMBER(), @message = ERROR_MESSAGE();
IF XACT_STATE() = -1
BEGIN
ROLLBACK
END
IF XACT_STATE() = 1 AND @trancount = 0
BEGIN
ROLLBACK
END
IF XACT_STATE() = 1 AND @trancount > 0
BEGIN
ROLLBACK TRANSACTION OuterProcedure
END
RAISERROR ('OuterProcedure: %d: %s', 16, 1, @error, @message)
END CATCH
END
我正在调用OuterProcedure
EXEC dbo.OuterProcedure
我收到类似
的错误对于嵌套过程,Msg 50000,Level 16,State 1,Procedure OuterProcedure,Line 34
OuterProcedure:50000:NestedProcedure:4922:ALTER TABLE ALTER COLUMN Column3失败,因为一个或多个对象访问此列
XACT_STATE()
为-1是正确的,因为错误是可以理解的,但为什么即使对于外部过程,XACT_STATE()
也变为-1?我只打算将嵌套过程回滚到保存点,无论它是否是运行时错误。有没有办法做到这一点?
答案 0 :(得分:2)
XACT_STATE()为-1表示该事务是不可容许的。一旦进入此注定状态,就不会再在事务中提交任何类型的写入。某些类错误会导致事务进入此状态。遗憾的是,很难清楚地描述导致这些错误的错误类型。看看这篇文章是为了深入探讨。
http://www.sommarskog.se/error_handling/Part2.html#classification
另请参阅TRY..CATCH和XACT_STATE文档中的说明。
https://docs.microsoft.com/en-us/sql/t-sql/functions/xact-state-transact-sql
如果你真的需要你的外部程序做一些工作,你可能需要考虑更高级别的解决方法,尽管内部程序会破坏事务。一种方法是使用标志重试外部过程,以避免在第一次尝试导致此类错误时重复trasaction-dooming错误。