我有一个数据库每周都会"发布"一次,也就是说我会发布一个备份供人们使用,并发布一个更新脚本用于从上周的版本升级(尽可能保留他们当前的数据)。这个脚本中当然包含了很多DDL -
您会注意到,我保留了事务并告诉他们手动完成,具体取决于发生了什么。我宁愿这是自动的,但考虑到整个过程总是一系列长时间的批处理,而且TRY块当然不能跨越批处理。因此最近添加了SET XACT_ABORT ON;以稍微减轻痛苦。无论如何,自那时以来我自己尝试过没有这个选项,对情况没有影响。无论如何。
最近,其中一个脚本有创建表的语句和其他语句来向现有表添加检查约束。我的一个用户运行了该脚本,并在约束上遇到错误;结果他有违反约束的预先存在的数据。好的,没问题,执行ROLLBACK。对了,不需要执行ROLLBACK,XACT_ABORT已经执行了。去修复数据行...完成。现在再试一次!噢...什么?这次没有在约束上出错,但它在CREATE TABLE语句上出错,说表已经存在...!嗯?它没有回滚吗?
我们最终从备份中恢复并重新修复数据并重新运行。但这与此无关。
所以,亲爱的读者们:这些表的创建如何在事务回滚后幸存下来?我怎样才能使它们不幸存?
编辑:好的,这里有一个您可以运行的示例。
CREATE TABLE
, ALTER TABLE
等等。它的基本结构如下:/*
HOW TO USE THIS SCRIPT
1. Run it against your existing DB
2. Check whether there were any errors
3. If there were, issue a rollback by highlighting this:
ROLLBACK
and executing it
4. If there weren't, issue a commit by highlighting this:
COMMIT
and executing it
5. !!! Not doing either of these will leave a transaction open, which will
probably cause all further queries to time out till you do !!!
*/
SET XACT_ABORT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
GO
-- Boilerplate checking and whatnot goes here
GO
-- Guts of operation, part 1
GO
-- Guts of operation, part 2
GO
-- Guts of operation, part 3
GO
-- . . .
GO
-- Guts of operation, part N
GO
-- Boilerplate cleanup stuff here
GO
您会注意到,我保留了事务并告诉他们手动完成,具体取决于发生了什么。我宁愿这是自动的,但考虑到整个过程总是一系列长时间的批处理,而且TRY块当然不能跨越批处理。因此最近添加了SET XACT_ABORT ON;以稍微减轻痛苦。无论如何,自那时以来我自己尝试过没有这个选项,对情况没有影响。无论如何。
最近,其中一个脚本有创建表的语句和其他语句来向现有表添加检查约束。我的一个用户运行了该脚本,并在约束上遇到错误;结果他有违反约束的预先存在的数据。好的,没问题,执行ROLLBACK。对了,不需要执行ROLLBACK,XACT_ABORT已经执行了。去修复数据行...完成。现在再试一次!噢...什么?这次没有在约束上出错,但它在CREATE TABLE语句上出错,说表已经存在...!嗯?它没有回滚吗?
我们最终从备份中恢复并重新修复数据并重新运行。但这与此无关。
所以,亲爱的读者们:这些表的创建如何在事务回滚后幸存下来?我怎样才能使它们不幸存?
编辑:好的,这里有一个您可以运行的示例。
USE tempdb;
GO
CREATE DATABASE example;
GO
USE example;
GO
CREATE TABLE foo (a INT);
GO
INSERT INTO foo
VALUES (100);
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
GO
ALTER TABLE foo ADD CHECK (a < 10);-- Gives error "The ALTER TABLE statement conflicted with the CHECK constraint…", as expected
GO
CREATE TABLE bar (b INT);
GO
ROLLBACK;-- Gives error "The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION." Huh? Where did our transaction go?
GO
SELECT *
FROM bar;-- Gives no error. Table still exists! NOT expected!
GO
USE tempdb;
GO
DROP DATABASE example;