我对以下模式的副作用和潜在问题感兴趣:
CREATE PROCEDURE [Name]
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
[...Perform work, call nested procedures...]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
END
据我所知,这种模式在与单个过程一起使用时是合理的 - 该过程将完成其所有语句而不会出现错误,或者将回滚所有操作并报告错误。
但是,当一个存储过程调用另一个存储过程来执行某些子工作单元时(了解较小的过程有时会单独调用),我看到一个与回滚相关的问题 - 一条信息性消息(级别 16) 发出,说明ROLLBACK TRANSACTION 请求没有相应的 BEGIN TRANSACTION。
。我认为这是因为子过程中的回滚总是回滚最外层的事务,而不仅仅是子过程中启动的事务。
如果发生任何错误(并且该错误作为 SQL 错误报告给客户端),我确实希望整个事情回滚并中止,我只是不确定来自外层试图执行的所有副作用回滚已经回滚的事务。也许在每个 TRY CATCH 层执行回滚之前检查 @@TRANCOUNT
?
最后是客户端 (Linq2SQL),它有自己的事务层:
try
{
var context = new MyDataContext();
using (var transaction = new TransactionScope())
{
// Some Linq stuff
context.SubmitChanges();
context.MyStoredProcedure();
transactionComplete();
}
}
catch
{
// An error occured!
}
如果在 MyStoredProcedure 内调用的存储过程“MySubProcedure”引发错误,我能否确定之前在 MyStoredProcedure 中完成的所有操作都将回滚,即由SubmitChanges会被回滚,最后那个错误会被记录吗?或者我需要改变我的模式以确保整个操作是原子的,同时仍然允许单独使用子部分(即子过程仍应具有相同的原子保护)
最佳答案
这是我们的模板(已删除错误日志记录)
这旨在处理
- Paul Randal 的文章 "No such thing as a nested transaction in SQL Server"
- 错误 266
- 触发回滚
说明:
所有 TXN 开始和提交/回滚必须配对,以便
@@TRANCOUNT
在进入和退出时相同@@TRANCOUNT
不匹配会导致错误 266,因为BEGIN TRAN
递增@@TRANCOUNT
COMMIT
递减@@TRANCOUNT
ROLLBACK
将@@TRANCOUNT
返回零
您无法减少当前范围的
@@TRANCOUNT
这就是您所认为的“内部交易”SET XACT_ABORT ON
抑制由不匹配的@@TRANCOUNT
导致的错误 266
并且还处理类似这样的问题 "SQL Server Transaction Timeout"在 dba.se 上这允许客户端 TXN(如 LINQ) 单个存储过程可能是分布式或 XA 事务的一部分,或者只是在客户端代码中启动的一个存储过程(例如 .net TransactionScope)
用法:
- 每个存储过程必须符合相同的模板
摘要
- 因此,创建的 TXN 数量不要超过您的需要
代码
CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE @starttrancount int
BEGIN TRY
SELECT @starttrancount = @@TRANCOUNT
IF @starttrancount = 0
BEGIN TRANSACTION
[...Perform work, call nested procedures...]
IF @starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND @starttrancount = 0
ROLLBACK TRANSACTION;
THROW;
--before SQL Server 2012 use
--RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO
注释:
由于
SET XACT_ABORT ON
,回滚检查实际上是多余的。然而,它让我感觉更好,不戴它看起来很奇怪,并且允许在您不希望它打开的情况下使用它Remus Rusanu有一个similar shell使用保存点。我更喜欢原子数据库调用,并且不像他们的文章那样使用部分更新
关于sql-server-2005 - 包含 TRY CATCH ROLLBACK 模式的嵌套存储过程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2073737/