通常情况下,你会想在开始添加BEGIN TRAN
,取出GO
语句,然后处理ROLLBACK TRAN
/COMMIT TRAN
与TRY..CATCH
块。
在处理DML时,虽然经常有语句必须在批处理的开始处,所以不能将它们包装在TRY..CATCH
块中。在这种情况下,你需要组装一个知道如何回滚的系统。
一个简单的系统就是在启动时备份数据库,如果有任何失败(假设您是唯一一个访问数据库的人)。另一种方法是记录每个成功运行的批处理,并具有相应的回滚脚本,以便在以后的批处理失败时运行该脚本以将所有内容都回收。这显然需要更多的工作(为每个脚本PLUS编写一个撤消脚本,充分测试回滚),并且如果在升级过程中人们仍然访问数据库,也可能会出现问题。
编辑: 这里有一个简单的TRY..CATCH
块与交易处理的例子:
BEGIN TRY
BEGIN TRANSACTION
-- All of your code here, with `RAISERROR` used for any of your own error conditions
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH
然而,TRY..CATCH
块不能跨批次(也许这就是我说的交易couldn”我在想什么的吨),所以在你的情况下,它可能会更类似于:
IF (OBJECT_ID('dbo.Error_Happened') IS NOT NULL)
DROP TABLE dbo.Error_Happened
GO
BEGIN TRANSACTION
<Some line of code>
IF (@@ERROR <> 0)
CREATE TABLE dbo.Error_Happened (my_id INT)
IF (OBJECT_ID('dbo.Error_Happened') IS NOT NULL)
BEGIN
<Another line of code>
IF (@@ERROR <> 0)
CREATE TABLE dbo.Error_Happened (my_id INT)
END
...
IF (OBJECT_ID('dbo.Error_Happened) IS NOT NULL)
BEGIN
ROLLBACK TRANSACTION
DROP TABLE dbo.Error_Happened
END
ELSE
COMMIT TRANSACTION
不幸的是,由于单独的批次从t他GO
陈述你不能使用GOTO
,你不能使用TRY..CATCH
,你不能持续跨越批次的变量。这就是为什么我使用创建表来表示错误的非常简单的技巧。
一个更好的方法是简单地有一个错误表,并在其中寻找行。请记住,您的ROLLBACK
也会在最后删除这些行。
交易可以跨越批次。 –
呵呵。不知道为什么我认为他们不能。感谢您指出了这一点。我已经删除了我的答案的一部分。我认为其余的依然是相关的。 –
感谢您的建议。 我的数据库是一种巨大的,所以我不会更喜欢备份/恢复。第二种方法对于我使每个执行的SQL的回滚语句更好。你能告诉我如何使用上面的例子来实现它。 非常感谢。 – user867198