在T-Sql中,rollback transaction
回滚除指定保存点名称之外的所有事务。要回滚部分修改,我们使用rollback transaction @save_point_name
。这是save transaction @save_point_name
必须提前说明的。如果引用的保存点已经回滚(从事务日志中删除),则会引发错误。同样,如果没有活动事务,则需要声明begin transaction @transaction_name
,并且可以以相同方式回滚。这样可以快速发现错误或使用try...catch
机制。
与rollback
不同,commit transaction @transaction_name
完全忽略其@transaction_name
部分,只执行提交,减少@@trancount
或结束事务。因此,无法知道或指定哪个(嵌套的)事务,或者就此而言 - 保存点正在(伪)提交。我知道交易并不意味着首先嵌套,因此存在保存点。
一种典型的方法是,在每个过程中,检查@@trancount
以确定是创建保存点还是开始新事务。然后,确认确定,检查事务状态并提交或回滚(或不执行任何操作)。
这种检查是很多样板文件,特别是当你有很多程序调用(多个)程序时,如果出现问题,只会回滚自己的操作。所以我的尝试是抽象交易,以便人们可以简单地写这样的东西。
create procedure RollBackOnlyMyActions
as
declare @SavePointName nvarchar(32) = N'RollBackToHere';
begin try
exec CreateSavePoint @SavePointName;
--do stuff
--call other procedures that may roll back only its actions
--do other stuff
exec CommitSavePoint @SavePointName;
end try
begin catch
exec RollBackSavePoint @SavePointName;
end catch
在哪里(为打印输出备用)
create procedure dbo.CreateSavePoint
@SavePointName nvarchar(32)
as
declare @Msg nvarchar(255);
print N'Preparing to create save point ['+@SavePointName+N'].';
print N'Checking not in an uncommitable transaction.';
if xact_state() != -1
begin
print N'Not in an uncommitable transaction. Checking for transaction existence.';
if @@TranCount = 0
begin
print N'No active transaction. Starting a new one.';
begin transaction @SavePointName;
end
else
begin
print N'In active transaction. Saving transaction point.';
save transaction @SavePointName;
end
end
else
begin
print N'In an uncommitable transaction. No use saving. Throwing exeption.';
set @Msg = N'Uncommitable transaction.';
throw 50000,@Msg,1;
end
go
create procedure dbo.CommitSavePoint
@SavePointName nvarchar(32)
as
declare @Msg nvarchar(255);
print N'Preparing to commit save point ['+@SavePointName+N'].';
print N'Checking not in an uncommitable transaction.';
if xact_state() != -1
begin
print N'Not in an uncommitable transaction. Checking transaction count.';
if @@trancount > 1
begin
print N'In nested transaction of '+convert(nvarchar(255),@@trancount)+N'. Committing once.';
end
else if @@trancount = 1
begin
print N'In outter transaction. Committing.';
end
else
begin
print N'No active transaction. Throw exception.';
set @Msg = N'No transaction to commit.';
throw 50000,@Msg,1;
end
commit transaction;
end
else
begin
print N'In an uncommitable transaction. Cannot commit. Throwing exeption.';
set @Msg = N'Uncommitable transaction.';
throw 50000,@Msg,1;
end
go
create procedure dbo.RollbackSavePoint
@SavePointName nvarchar(32)
as
declare @Msg nvarchar(255);
print N'Prepare to rollback savepoint ['+@SavePointName+N']';
print N'Checking not in an uncommitable transaction.';
if xact_state() != -1
begin
print N'Not in an uncommitable transaction. Trying rollback';
begin try
rollback transaction @SavePointName;
end try
begin catch
print N'Something went wrong. Rethrowing exception.';
throw;
end catch
end
else
begin
print N'In an uncommitable transaction. No use rolling back. Throwing exeption.';
set @Msg = N'Uncommitable transaction.';
throw 50000,@Msg,1;
end
go
这没有用。当我得到一个
Msg 266, Level 16, State 2, Procedure CreateSavePoint, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
首次调用CreateSavePoint之后。也就是说,似乎sql server不喜欢跨多个程序管理事务。
因此。有没有解决此问题的方法,例如,一种抑制此错误的方法?或者我在这里错过了一个重要的概念?
答案 0 :(得分:0)
回滚问题可以通过使用SET XACT_ABORT ON来解决,这是“自动回滚”(简单)并且可以抑制错误266.