Sqlserver的Transaction作Rollback的時候要當心(轉載)

仔細研究了下,發現sql server裏面的explicit transaction(顯示事務)仍是有點複雜的。如下是有些總結:html

Commit transaction 會提交全部嵌套的transaction修改。可是若是嵌套的transaction裏面有rollback tran to save point, 那麼save point以後的部分會revert掉。sql

delete from dbo.numbertable

begin tran out1

     insert into dbo.numbertable values(1)

     insert into dbo.numbertable values(2)

     

     begin tran inn1

          insert into dbo.numbertable values(3)

          insert into dbo.numbertable values(4)

     save tran inn1SavePoint

          insert into dbo.numbertable values(5)

     rollback tran inn1SavePoint

     commit tran inn1

commit tran out1

 

@@TRANCOUNT能夠用來記錄當前session transaction的個數,對於嵌套的transaction來說,每次begin transaction都讓它加一,每次commit tran都會讓它減一。因此在語句裏面能夠經過select @@TRANCOUNT 來檢查當前是否在一個transaction裏面。若是當前@@TRANCOUNT爲0,那調用commit仍是rollback都會出現語句錯誤。在嵌套的transaction裏面,rollback是很特殊的,它會直接把@@TRANCOUNT設置爲0。session

begin tran

begin tran

begin tran

print @@trancount

rollback tran

print @@trancount

 

對於嵌套的transaction來說,rollback的寫法是很特殊。若是嵌套,rollback transaction後面是不能帶transaction的name的,要帶也只能是最外面的transaction的name。Rollback會拋棄全部嵌套transaction在rollback語句以前的修改。不過Rollback以後的更新依然會提交就是了,緣由在於:rollback以後,@@trancount爲0,那麼rollback以後的語句就不屬於explicit transaction, 屬於autocmmit transaction了,自動提交。spa

delete from dbo.numbertable

begin tran t1

     insert into dbo.numbertable values(1)

     

     begin tran t2

          insert into dbo.numbertable values(2)

     rollback tran

     print 'after rollback in innert transaction, the transaction count is: '+cast(@@trancount, varchar(5))

     insert into dbo.numbertable values(3)

--commit tran

select * from dbo.numbertable


存儲過程裏面也能夠begin transaction,若是調用存儲過程的地方也begin transaction,那麼這種狀況也屬於嵌套transaction,若是在存儲過程裏面rollback,獲得的結果和上面同樣。可是有一點特殊的地方在與,執行存儲過程結束的時候會比較開始執行存儲過程的@@trancount和結束時候@@trancount的值,若是不同,Sqlserver會給出一個消息像「Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.」這個給出的消息並不會影響其後的執行。code

CREATE PROCEDURE [dbo].[AddNumber]       

AS

BEGIN

     begin tran 

          insert into dbo.numbertable values(1)

          insert into dbo.numbertable values(2)

          insert into dbo.numbertable values(3)

     rollback tran

END

delete from dbo.numbertable

begin tran out1

exec dbo.addnumber

print @@trancount

insert into dbo.numbertable values(3)

select * from dbo.numbertable

 

若是在存儲過程裏面作rollback了,那到外面再作commit或者rollback都是沒有效果的而且會報錯,由於嵌套transaction內部的transaction一旦調用了rollback,@@trancount就爲0了,在外面commit或rollback就會直接報錯。好比以下sp,我想像在最外面rollback,那就出錯了,由於sp裏面語句rollback了。最後表裏面始終會插入值3。server

delete from dbo.numbertable

begin tran out1

exec dbo.addnumber

print @@trancount

insert into dbo.numbertable values(3)

rollback tran out1

select * from dbo.numbertable

 

 

因此對於嵌套的transaction來說,若是內部transaction一旦rollback,就會給外部的transaction留下一個大坑。爲了解決這個爲題,有兩種解決方案:htm

1.在外部的transaction裏面檢查@@trancount,若是這個值跟你代碼begin tran的時候一致,那說明內部transaction沒有rollback,那能夠繼續commit或者rollback。blog

delete from dbo.numbertable

begin tran t1

     insert into dbo.numbertable values(1)

     

     begin transaction t2

          insert into dbo.numbertable values(2)

     rollback tran

 

     if @@trancount = 1 

     begin

          insert into dbo.numbertable values(3)

          commit tran

     end

 

2.在全部的內部transaction裏面,只能commit,不能rollback。若是必須rollback,那怎麼辦?save point就能夠派上用場了。好比sp改爲這樣子:事務

ALTER PROCEDURE [dbo].[AddNumber]        

AS

BEGIN

     begin tran 

     save tran pp

          insert into dbo.numbertable values(1)

          insert into dbo.numbertable values(2)

          insert into dbo.numbertable values(3)

     rollback tran pp

     commit tran

END

 

begin tran out1

exec dbo.addnumber

print @@trancount

insert into dbo.numbertable values(3)

commit tran out1

 

原文連接ci

相關文章
相關標籤/搜索