如何自动回滚失败的 (SSMS) SQL 脚本中的所有“批次”
How to automatically rollback all “batches” in a (SSMS) SQL script that fails
我有 SQL 个脚本,它们将通过 SQL Server Management Studio 在 SQL Server 2012 数据库上执行。使用 GO
语句将脚本分成多个批次。如果任何批次中的任何更新出错,我希望一切都回滚。
我已经尝试使用 XACT_ABORT ON
,但它没有像我预期的那样工作:
begin transaction txn
go
set xact_abort on
go
insert into Table1 (Col1) values (1)
go
insert into Table1 (Col1) values (2/0)
go
insert into Table1 (Col1) values (3)
go
create procedure Proc1
as
begin
select * from Table1
end
go
commit transaction txn
go
当运行此脚本时,插入#2 失败并回滚插入#1。但是,插入 #3 成功并创建了存储过程。
有没有办法让一个插入失败,所有插入都失败?
请注意,我的实际脚本可能包含数百个批次,其中一些批次有数百种不同类型的更新(插入、更新、更改、删除等)。因此,我宁愿不必向批处理中添加任何额外的代码,即我想将它们全部打包在一个大事务中。
感谢任何建议。
我就是这样做的,它不会像你想象的那么简单,但它对我有用。
我在脚本中做的第一件事是:
IF (SELECT OBJECT_ID('tempdb..#tmpErrors')) IS NOT NULL DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error int)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRANSACTION
GO
然后insert/updates。每次操作后执行此操作:
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
然后在脚本的最后添加:
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT N'The transacted portion of the database update succeeded.'
COMMIT TRANSACTION
END
ELSE PRINT N'The transacted portion of the database update failed.'
GO
DROP TABLE #tmpErrors
GO
将所有这些应用到您正在尝试的脚本 运行 将是这样的:
-- this on top
IF (SELECT OBJECT_ID('tempdb..#tmpErrors')) IS NOT NULL DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error int)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRANSACTION
GO
insert into Table1 (Col1) values (1)
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
insert into Table1 (Col1) values (2/0)
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
insert into Table1 (Col1) values (3)
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
-- this at the end
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT N'The transacted portion of the database update succeeded.'
COMMIT TRANSACTION
END
ELSE PRINT N'The transacted portion of the database update failed.'
GO
DROP TABLE #tmpErrors
GO
下面是我如何使用 TRY/CATCH 块来做到这一点。您可以在此处阅读更多相关信息。 https://msdn.microsoft.com/en-us/library/ms175976.aspx
begin transaction
begin try
insert into Table1 (Col1) values (1);
insert into Table1 (Col1) values (2/0);
insert into Table1 (Col1) values (3);
commit transaction;
end try
begin catch
select ERROR_NUMBER() AS ErrorNumber
, ERROR_MESSAGE() AS ErrorMessage;
rollback transaction;
end catch;
我有 SQL 个脚本,它们将通过 SQL Server Management Studio 在 SQL Server 2012 数据库上执行。使用 GO
语句将脚本分成多个批次。如果任何批次中的任何更新出错,我希望一切都回滚。
我已经尝试使用 XACT_ABORT ON
,但它没有像我预期的那样工作:
begin transaction txn
go
set xact_abort on
go
insert into Table1 (Col1) values (1)
go
insert into Table1 (Col1) values (2/0)
go
insert into Table1 (Col1) values (3)
go
create procedure Proc1
as
begin
select * from Table1
end
go
commit transaction txn
go
当运行此脚本时,插入#2 失败并回滚插入#1。但是,插入 #3 成功并创建了存储过程。
有没有办法让一个插入失败,所有插入都失败?
请注意,我的实际脚本可能包含数百个批次,其中一些批次有数百种不同类型的更新(插入、更新、更改、删除等)。因此,我宁愿不必向批处理中添加任何额外的代码,即我想将它们全部打包在一个大事务中。
感谢任何建议。
我就是这样做的,它不会像你想象的那么简单,但它对我有用。
我在脚本中做的第一件事是:
IF (SELECT OBJECT_ID('tempdb..#tmpErrors')) IS NOT NULL DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error int)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRANSACTION
GO
然后insert/updates。每次操作后执行此操作:
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
然后在脚本的最后添加:
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT N'The transacted portion of the database update succeeded.'
COMMIT TRANSACTION
END
ELSE PRINT N'The transacted portion of the database update failed.'
GO
DROP TABLE #tmpErrors
GO
将所有这些应用到您正在尝试的脚本 运行 将是这样的:
-- this on top
IF (SELECT OBJECT_ID('tempdb..#tmpErrors')) IS NOT NULL DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error int)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRANSACTION
GO
insert into Table1 (Col1) values (1)
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
insert into Table1 (Col1) values (2/0)
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
insert into Table1 (Col1) values (3)
GO
IF @@ERROR <> 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK;END
IF @@TRANCOUNT = 0 BEGIN INSERT INTO #tmpErrors (Error) VALUES (1); BEGIN TRANSACTION;END
GO
-- this at the end
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT N'The transacted portion of the database update succeeded.'
COMMIT TRANSACTION
END
ELSE PRINT N'The transacted portion of the database update failed.'
GO
DROP TABLE #tmpErrors
GO
下面是我如何使用 TRY/CATCH 块来做到这一点。您可以在此处阅读更多相关信息。 https://msdn.microsoft.com/en-us/library/ms175976.aspx
begin transaction
begin try
insert into Table1 (Col1) values (1);
insert into Table1 (Col1) values (2/0);
insert into Table1 (Col1) values (3);
commit transaction;
end try
begin catch
select ERROR_NUMBER() AS ErrorNumber
, ERROR_MESSAGE() AS ErrorMessage;
rollback transaction;
end catch;