zoukankan      html  css  js  c++  java
  • SqlServer中嵌套事务使用--事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配 --根本问题

    转自  :SqlServer中嵌套事务使用--事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配 --根本问题

    问题:

    1. System.Data.SqlClient.SqlException (0x80131904): EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 1,当前计数 = 0。

    2. EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 0,当前计数 = 1。

    后面的内容,是我之前写的东西,主要是一些测试代码,但是呢,我没有很深入的理解。现在直接说清楚本质的东西,把后面的精华再提上来说。 

    • 提交的事务不能撤销或回滚。
    • 当不存在打开的事务时,@@trancount 等于 0。
    • 执行 begin tran [tranName]语句将 @@trancount 增加 1。
    • 执行commit tran [tranName]语句将 @@trancount 减小 1。
    • 执行 rollback tran  会回滚整个事务并设置@@trancount 为 0。
    • 执行 " rollback tran  tranName"语句时有两种情况:

    if(tranName 之前 是用 " Save Tran tranName" 建立的 )  @@trancount值不变

    否则,@trancount 减小1              

          注意:save tran 命令,不会使@@trancount加1

    分析:

    只要提交或者回滚事务后,程序内部改变了事务参数@@TRANCOUNT,就会出上述的错误,无一例外。

    试图直接用Sql "  set @@trancount = 1;",这是sqlserver 不允许做的。

    各位,出现上面的错误,最多的可能是在嵌套事务中。

    如果不嵌套:没有begin tran前,@@trancount为0;  begin tran后,@@trancount  此时为1;完事后就commit或rollback,@@trancount  此时为0;--不般我们是写不错的。

    嵌套呢

        看看我之前写的一个存储过程:

                  

    [sql] view plaincopy
     
    1. declare @trancount int --commit,rollback只控制本存储过程   
    2.     set @trancount = @@trancount;  
    3.       
    4.     if (@trancount=0) /*判断事务记数,根据情况确定使用保存点或者新建一个事务*/   
    5.         begin tran current_tran--当前事务点,rollback、commit都从这里开始    
    6.     else  
    7.         save tran current_tran  
    [sql] view plain copy
     
    1. declare @trancount int --commit,rollback只控制本存储过程  
    2.     set @trancount = @@trancount;  
    3.       
    4.     if (@trancount=0) /*判断事务记数,根据情况确定使用保存点或者新建一个事务*/   
    5.         begin tran current_tran--当前事务点,rollback、commit都从这里开始   
    6.     else  
    7.         save tran current_tran  

    .......

    ....做事去了

    .......

    [sql] view plaincopy
     
    1. if @error_code != 0 or @logErrorCode != 1  
    2.         begin  
    3.             rollback tran current_tran  
    4.             set @error_code = -1; -- 失败   
    5.         end  
    6.     else  
    7.         begin  
    8.             commit tran current_tran  
    9.             set @error_code = 1; -- 成功   
    10.          end  
    [sql] view plain copy
     
    1. if @error_code != 0 or @logErrorCode != 1  
    2.         begin  
    3.             rollback tran current_tran  
    4.             set @error_code = -1; -- 失败  
    5.         end  
    6.     else  
    7.         begin  
    8.             commit tran current_tran  
    9.             set @error_code = 1; -- 成功  
    10.          end  

    有没有问题?(current_tran是保存点哈,不明白的,后面有比较详细的介绍)

    我用了好久了(在一个项目里面),可是突然有一天,也就是今天,它出事了。原因嘛,虽然写的是嵌套的,之前都没有嵌套调到过。

    我在外围开了一个事务,再来调这个存储过程,当它 commit tran current_tran 时(rollback tran current_tran是不会有事的),会出什么错误?如果你不能很明确的告诉我,说明你还没有理解得深刻。做个选择吧?

    1."...BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 0,当前计数 = 1。"

    2."...BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 1,当前计数 = 0。

    答案:【2】。

    线索分析:我是在外部开了一个事务的,所以在未进入该存储过程以前@@trancount的值应该为1;进入时,save tran current_tran, @@trancount值没有变;完事的,执行commit tran current_tran,@@trancount的值应该为0;--所以,进入前,出来后,@@trancount值发生了改变,SqlServer不干了(原因,自己去想吧:拆散了begin tran 配对)。

    怎么解决

     1.进入子事务前先记录@@trancount,我们用变量@trancount来记录。

     2. 提交子事务前,先判断之前的@trancount是否为0;为0表示"该事务"前没有事务调用,可以直接提交事务;不为0,表明进入该事务前已经有一个事务,该事务是子事务,不能提交。

    [sql] view plaincopy
     
    1. -- 如果当前计数为0,则提交.    
    2.          -- 因为Commit tran ,@@TRANCOUNT会减1。嵌套事务时,调用该存在过程(作为子过程,此时@@TRANCOUNT > 0),   
    3.          -- 只是保存了tran, @@TRANCOUNT没有发生改变;直接Commit会使@@TRANCOUNT减1,会打破事务对(Begin Tran)   
    4.         if(@trancount = 0)  
    5.         begin  
    6.             commit tran current_tran  
    7.         end  
    8.         set @error_code = 1; -- 成功  
    [sql] view plain copy
     
    1. -- 如果当前计数为0,则提交.   
    2.          -- 因为Commit tran ,@@TRANCOUNT会减1。嵌套事务时,调用该存在过程(作为子过程,此时@@TRANCOUNT > 0),  
    3.          -- 只是保存了tran, @@TRANCOUNT没有发生改变;直接Commit会使@@TRANCOUNT减1,会打破事务对(Begin Tran)  
    4.         if(@trancount = 0)  
    5.         begin  
    6.             commit tran current_tran  
    7.         end  
    8.         set @error_code = 1; -- 成功  

     

  • 相关阅读:
    HDU 1950 Bridging signals(LIS)
    PKU 1094 Sorting It All Out(拓扑排序)
    中国剩余定理(孙子定理)详解
    51Nod 1079
    翻转游戏
    不构造树的情况下验证先序遍历
    图说流程管理
    从架构到流程
    POS(Plan Operation Support 和 OES(Operation Enable Support)
    流程规划方法→POS法
  • 原文地址:https://www.cnblogs.com/zhangwei99com/p/7815586.html
Copyright © 2011-2022 走看看