我有这个交易:
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。:我知道在尝试添加列之前我可以检查列是否存在,但我想知道为什么事务的工作方式与我期望的一样。
感谢。
答案 0 :(得分:1)
忽略设置位,您的脚本:
COMMIT
因此,当然,这些初步变化已经应用。您可以设置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
并且您必须在每个包含错误的批次中执行相同操作。