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 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 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 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  
[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 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; -- 成功  
[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; -- 成功  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM