2014-03-19 45 views
0

我有這樣的交易:爲何在發生錯誤時執行部分交易?

BEGIN TRANSACTION 
SET QUOTED_IDENTIFIER ON 
SET ARITHABORT ON 
SET NUMERIC_ROUNDABORT OFF 
SET CONCAT_NULL_YIELDS_NULL ON 
SET ANSI_NULLS ON 
SET ANSI_PADDING ON 
SET ANSI_WARNINGS ON 
COMMIT 

BEGIN TRANSACTION 

delete from Versions; 
insert into Versions(Version) VALUES('1.0.0.0'); 
GO 

ALTER TABLE dbo.MyTable ADD 
    MyNewColumn varchar(1000) NULL 

ALTER TABLE dbo.MyTable SET (LOCK_ESCALATION = TABLE) 
GO 
COMMIT 

在第一時間版本表是空的,並且在MyTable的我列「MyNewColumn」,所以當我嘗試添加新的專欄中,我得到一個錯誤。但是,當我執行腳本時,表版本與數據庫版本有一個記錄。

爲什麼?如果我正在使用事務並且只有一個提交,那麼我認爲任何這些語句都不會在數據庫中進行更改。

我想如果其中一個語句失敗,任何語句都不能更改數據庫。

P.D .:我知道我可以在嘗試添加它之前檢查列是否存在,但我想知道爲什麼事務按我的預期工作。

謝謝。

+2

交易將執行所有操作,但直到最後纔會提交。所以插入操作會插入一個未提交的記錄,該記錄將在您的交易範圍內可見。如果你期望錯誤將代碼包裝在try catch塊中並處理它們 – Tanner

+1

要添加到Tanner所說的內容中,您需要捕獲錯誤併發出明確的ROLLBACK。發生錯誤時,事務不會自動回滾。你需要這樣做。 –

回答

1

忽略安裝位,你的腳本:

  • 啓動事務
  • 做了刪除
  • 確實插入
  • 運行的一些代碼生成錯誤
  • 做了COMMIT

所以,當然th已經應用了初始更改。您可以設置XACT_ABORT上,這將導致任何一批生成錯誤回滾事務,但你仍然需要非常小心:

create table T(ID int) 
go 
set xact_abort on 
go 
begin transaction 
go 
insert into T(ID) values (1) 
go 
alter table T add ID int null 
go 
insert into T(ID) values (2) 
go 
commit 
go 
select * from T 

可生產這些消息:

(1 row(s) affected) 
Msg 2705, Level 16, State 4, Line 1 
Column names in each table must be unique. Column name 'ID' in table 'T' 
is specified more than once. 

(1 row(s) affected) 
Msg 3902, Level 16, State 1, Line 1 
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION. 

(1 row(s) affected) 

而且還表中有一行包含2。爲什麼?因爲錯誤通過回滾終止了事務,但是接下來的批處理(包含insert into T(ID) values (2))在沒有顯式事務存在的情況下運行。沒有太多的幫助,當涉及到錯誤處理跨越批次,除了一些手動步驟,例如,你可以得到:

create table T(ID int) 
go 
set xact_abort on 
go 
begin transaction 
go 
insert into T(ID) values (1) 
go 
alter table T add ID int null 
go 
if @@TRANCOUNT = 0 goto errored 
insert into T(ID) values (2) 
errored: 
go 
if @@TRANCOUNT = 0 goto errored 
commit 
errored: 
go 
select * from T 

而且你必須做相同的,可能遵循一個包含錯誤的每批。

相關問題