嵌套事务的问题

嵌套事务有几个特征, 帮助中这么说;

Microsoft? SQL Server? 忽略提交内部事务。根据最外部事务结束时采取的操作,将提交或者回滚事务。如果提交外部事务,则内层嵌套的事务也会提交。如果回滚外部事务,则不论此前是否单独提交过内层事务,所有内层事务都将回滚。

对 COMMIT TRANSACTION 或 COMMIT WORK 的每个调用都应用于最后执行的 BEGIN TRANSACTION。如果嵌套 BEGIN TRANSACTION 语句,那么 COMMIT 语句只应用于最后一个嵌套的事务,也就是在最内层的事务。即使嵌套事务内部的 COMMIT TRANSACTION transaction_name 语句引用外部事务的事务名,该提交也只应用于最内层的事务。

ROLLBACK TRANSACTION 语句的 transaction_name 参数引用一组命名的嵌套事务的内层事务是非法的,transaction_name 只能引用最外部事务的事务名。如果在一组嵌套事务的任意级别执行使用外部事务名称的 ROLLBACK TRANSACTION transaction_name 语句,那么所有的嵌套事务都将回滚。如果在一组嵌套事务的任意级别执行没有 transaction_name 参数的 ROLLBACK WORK 或 ROLLBACK TRANSACTION 语句,那么它将回滚所有嵌套事务,包括最外部事务。

@@TRANCOUNT 函数记录当前事务的嵌套级。每个 BEGIN TRANSACTION 语句使 @@TRANCOUNT 加 1。每个 COMMIT TRANSACTION 或 COMMIT WORK 语句使 @@TRANCOUNT 减 1。没有事务名的 ROLLBACK WORK 或 ROLLBACK TRANSACTION 语句将回滚所有嵌套事务,并使 @@TRANCOUNT 减小到 0。使用一组嵌套事务中最外部事务的事务名称的 ROLLBACK TRANSACTION 将回滚所有嵌套事务,并使 @@TRANCOUNT 减到 0。在无法确定是否已经在事务中时,可以用 SELECT @@TRANCOUNT 语句确定 @@TRANCOUNT 是 1 还是更大。如果 @@TRANCOUNT 是 0,则表明不在事务中。

如何解决嵌套显式事务的问题,我举了一个例子:

嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔
--  create a table  for  testing
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔Create Table T1(v 
int  check (v < 100 ))      --  v必须小于100
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔
-- create first proc  to  insert data
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔Create Proc InnerTrans
嵌套事务的问题 - 【ASKD】 - 我心飞翔
AS
嵌套事务的问题 - 【ASKD】 - 我心飞翔Begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔    begin tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔    insert into T1 values(
1 --  this should be ok
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
if  @@ error <> 0
嵌套事务的问题 - 【ASKD】 - 我心飞翔        begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔            rollback tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔            return 
- 1
嵌套事务的问题 - 【ASKD】 - 我心飞翔        
end
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
嵌套事务的问题 - 【ASKD】 - 我心飞翔    insert into T1 values(
200 --  违反了约束
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
if  @@ error <> 0
嵌套事务的问题 - 【ASKD】 - 我心飞翔        begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔            rollback tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔            return 
- 1
嵌套事务的问题 - 【ASKD】 - 我心飞翔        
end
嵌套事务的问题 - 【ASKD】 - 我心飞翔    commit tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔    return 
1
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
-- ok here
嵌套事务的问题 - 【ASKD】 - 我心飞翔
End
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔Create Proc OuterTran
嵌套事务的问题 - 【ASKD】 - 我心飞翔
AS
嵌套事务的问题 - 【ASKD】 - 我心飞翔Begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔    begin tran tran2
嵌套事务的问题 - 【ASKD】 - 我心飞翔    insert into T1 values(
2 )         --  ok  now
嵌套事务的问题 - 【ASKD】 - 我心飞翔    declare  @invokecode 
int
嵌套事务的问题 - 【ASKD】 - 我心飞翔    exec @invokecode
= innerTrans
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
if (@invokecode =- 1 )        
嵌套事务的问题 - 【ASKD】 - 我心飞翔        rollback tran tran2
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
else
嵌套事务的问题 - 【ASKD】 - 我心飞翔        commit tran tran2
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
嵌套事务的问题 - 【ASKD】 - 我心飞翔
End
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔
select   *  from T1
嵌套事务的问题 - 【ASKD】 - 我心飞翔exec innerTrans    
--  worked ok
嵌套事务的问题 - 【ASKD】 - 我心飞翔exec OuterTran    
-- does  not  work
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔
--  How  to  Modify?
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔
嵌套事务的问题 - 【ASKD】 - 我心飞翔alter Proc InnerTrans
嵌套事务的问题 - 【ASKD】 - 我心飞翔
AS
嵌套事务的问题 - 【ASKD】 - 我心飞翔Begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔    begin tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔    save tran ttt    
-- savepoint here
嵌套事务的问题 - 【ASKD】 - 我心飞翔    insert into T1 values(
1 --  this should be ok
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
if  @@ error <> 0
嵌套事务的问题 - 【ASKD】 - 我心飞翔        begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔            rollback tran ttt
嵌套事务的问题 - 【ASKD】 - 我心飞翔            commit tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔             return 
- 1
嵌套事务的问题 - 【ASKD】 - 我心飞翔        
end
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
嵌套事务的问题 - 【ASKD】 - 我心飞翔    insert into T1 values(
200 --  违反了约束
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
if  @@ error <> 0
嵌套事务的问题 - 【ASKD】 - 我心飞翔        begin
嵌套事务的问题 - 【ASKD】 - 我心飞翔            rollback tran ttt
嵌套事务的问题 - 【ASKD】 - 我心飞翔            commit tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔            return 
- 1
嵌套事务的问题 - 【ASKD】 - 我心飞翔        
end
嵌套事务的问题 - 【ASKD】 - 我心飞翔    commit tran tran1
嵌套事务的问题 - 【ASKD】 - 我心飞翔    return 
1
嵌套事务的问题 - 【ASKD】 - 我心飞翔    
-- ok here
嵌套事务的问题 - 【ASKD】 - 我心飞翔
End
嵌套事务的问题 - 【ASKD】 - 我心飞翔
0
0
我习惯判断@@TRANCOUNT然后选择是BEGIN TRANSACTION还是用SAVE TRANSACTION

例如:

--BEGIN TRANSACTION

SELECT @@TRANCOUNT

DECLARE @ROLLBACKIT BIT
DECLARE @SAVEPOINT NVARCHAR(36)
IF @@TRANCOUNT = 0 BEGIN TRANSACTION ELSE BEGIN SET @SAVEPOINT=NEWID() SAVE TRANSACTION @SAVEPOINT END
SELECT @SAVEPOINT
--DO SOME THING
IF @ROLLBACKIT=1
BEGIN
IF @SAVEPOINT IS NULL ROLLBACK TRANSACTION ELSE ROLLBACK TRANSACTION @SAVEPOINT
END
ELSE
BEGIN
IF @SAVEPOINT IS NULL COMMIT TRANSACTION
END

SELECT @@TRANCOUNT
--ROLLBACK TRANSACTION
如果在同一个命名范围中需要嵌套,那么就要是 @SAVEPOINT1,@SAVEPOINT2...了.

ransaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

这个问题主要是因为事务的嵌套引起的。被嵌套的事务里面如果出现错误如何处理是个主要的问题。一般情况下都是用RollBack Transaction,但是这样做是不对的。

在SqlServer里,嵌套事务的层次是由@@TranCount全局变量反映出来的。每一次Begin Transaction都会引起@@TranCount加1。而每一次Commit Transaction都会使@@TranCount减1,而RollBack Transaction会回滚所有的嵌套事务包括已经提交的事务和未提交的事务,而使@@TranCount置0。举个例子:
Begin Transaction -- @@TranCount = 1
BeginTransaction -- @@TranCount = 2
BeginTransaction -- @@TranCount = 3
Commit Transaction -- @@TranCount = 2
Commit Transaction -- @@TranCount = 1
Commit Transaction -- @@TranCount = 0
如果被嵌套的事务中出现错误,最简单的方法应该是无论如何都将它提交,但是应该返回错误码(如-1),从而使@@TranCount 减1 这样外层事务在回滚或者提交的时候能够保证外层事务在开始的时候和结束的时候保持一致。由于里层事务返回了错误码,因此外层事务(最外层)可以回滚事务, 这样里面已经提交的事务也可以被回滚而不出现错误。

在项目中常常出现这样的情况,一个存储过程里面用了事务,但是不能保证它会被别的存储过程调用,如果单独调用的话,出现错误可以直接回滚,但是如果是被别的存储过程调用的话,RollBack 就会出错了。因此需要一种机制来区分:

declare @localTranCount int
set @localTranCount = 0
Begin Transaction
set @localTranCount = @localTranCount +1
…………
goto Error
Begin Transaction
set @localTranCount = @localTranCount +1
…………
goto Error
 Commit Transaction
Commit Transaction
Return 0
Error:
IF(@@TranCount = @localTranCount) RollBack Transaction
Else Commit Transaction
Return @Error

转载于:https://www.cnblogs.com/genghechuang/archive/2011/10/17/2215639.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值