仔細研究了下,發(fā)現sql server里面的explicit transaction還是有點(diǎn)復雜的。以下是有些總結:
· Commit transaction 會(huì )提交所有嵌套的transaction修改。但是如果嵌套的transaction里面有rollback tran to save point, 那么save point之后的部分會(huì )revert掉。
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可以用來(lái)記錄當前session transaction的個(gè)數,對于嵌套的transaction來(lái)講,每次begin transaction都讓它加一,每次commit tran都會(huì )讓它減一。所以在語(yǔ)句里面可以通過(guò)select @@TRANCOUNT 來(lái)檢查當前是否在一個(gè)transaction里面。如果當前@@TRANCOUNT為0,那調用commit還是rollback都會(huì )出現語(yǔ)句錯誤。在嵌套的transaction里面,rollback是很特殊的,它會(huì )直接把@@TRANCOUNT設置為0。
begin tran
begin tran
begin tran
print @@trancount
rollback tran
print @@trancount
· 對于嵌套的transaction來(lái)講,rollback的寫(xiě)法是很特殊。如果嵌套,rollback transaction后面是不能帶transaction的name的,要帶也只能是最外面的transaction的name。Rollback只會(huì )拋棄所有嵌套transaction在rollback語(yǔ)句之前的修改。Rollback之后的更新依然提交就去了,原因在于:rollback之后,@@trancount為0,那么rollback之后的語(yǔ)句就不屬于explicit transaction, 屬于autocmmit transaction了,自動(dòng)提交。
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
· 存儲過(guò)程里面也可以begin transaction,如果調用的地方也begin transaction,那么這種情況也屬于嵌套transaction,如果在存儲過(guò)程里面rollback,得到的結果和上面一樣。但是有一點(diǎn)特殊的地方在與,執行存儲過(guò)程結束的時(shí)候會(huì )比較開(kāi)始執行sp的@@trancount和結束時(shí)候@@trancount的值,如果不一樣,它會(huì )給出一個(gè)消息像“Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.”這個(gè)給出的消息并不會(huì )影響其后的執行。
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
· 如果在sp里面rollback了,那到外滿(mǎn)做commit, 或者rollback都是沒(méi)有效果并且出錯了,因為嵌套的transaction內部transaction一旦調用了rollback,@@trancount就為0了,在外滿(mǎn)commit,rollback直接出錯。比如如下sp,我想像在最外面rollback,那就出錯了,因為sp里面語(yǔ)句rollback了。表里面始終會(huì )插入值3。
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來(lái)講,如果內部transaction一旦rollback,就會(huì )給外部的transaction留下一個(gè)大坑。為了解決這個(gè)為題,有兩種解決方案:
1. 在外部的transaction里面檢查@@trancount,如果這個(gè)值跟你代碼begin tran的可以一致,那說(shuō)明內部transaction沒(méi)有rollback,那可以繼續commit或者rollback。
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就可以派上用場(chǎng)了。比如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
聯(lián)系客服