如果任何语句失败,将回滚的 SQL 查询

Posted

技术标签:

【中文标题】如果任何语句失败,将回滚的 SQL 查询【英文标题】:SQL query that'll rollback if any statements fails 【发布时间】:2011-01-15 09:11:41 【问题描述】:

我想编写一个执行多个单独 SQL 语句的 SQL 脚本;如果这些语句中的任何一个失败,我想回滚整个事务。所以,像:

BEGIN TRANSACTION

insert into TestTable values (1)
insert into TestTable values (2)
insert into TestTabe values (3)

--if any of the statements fail
ROLLBACK
--else
COMMIT

这是针对 MS SQL 2008 的。有什么我可以做的吗?也许是某种异常处理?

我意识到在我的示例中我可以检查这些值的 TestTable 并确定语句是否以这种方式失败。但实际上我的 SQL 会复杂得多,我宁愿抽象自己不知道 SQL 在做什么。

【问题讨论】:

【参考方案1】:

我很懒,在我的所有陈述中都添加了这一行

SET XACT_ABORT ON

http://technet.microsoft.com/en-us/library/ms188792.aspx

当 SET XACT_ABORT 为 ON 时,如果 Transact-SQL 语句引发一个 运行时错误,整个事务 被终止并回滚。

当 SET XACT_ABORT 为 OFF 时,在某些 仅适用于 Transact-SQL 语句 引发错误的回滚 交易继续 加工。取决于 错误的严重性,整个 甚至可以回滚事务 当 SET XACT_ABORT 为 OFF 时。关是 默认设置。

编译错误,例如语法错误, 不受 SET XACT_ABORT 影响。

XACT_ABORT 必须为数据设置为 ON 隐式中的修改语句 或针对大多数人的明确交易 OLE DB 提供程序,包括 SQL 服务器。唯一的这种情况 选项不是必需的,如果 provider 支持嵌套事务。 有关详细信息,请参阅分布式 查询和分布式事务。

SET XACT_ABORT 的设置被设置 在执行或运行时而不是在 解析时间。

【讨论】:

【参考方案2】:

这是我过去做过的一种方式:

Declare @HasError int;
set @HasError = 0;

BEGIN TRANSACTION

insert into TestTable values (1)
if (@@ERROR != 0)
    set @HasError = 1
insert into TestTable values (2)
if (@@ERROR != 0)
    set @HasError = 1
insert into TestTabe values (3)
if (@@ERROR != 0)
    set @HasError = 1

if @HasError > 0
    ROLLBACK TRANSACTION
ELSE
    COMMIT TRANSACTION

【讨论】:

另一个有趣的建议。谢谢。虽然我会使用与@error 不同的名称,但更清楚的是它与@ERROR 不同。 是的,我现在头疼的少了:)【参考方案3】:

自 2005 年以来,SQL Server 就提供了异常支持:

BEGIN TRY
    BEGIN TRAN

    INSERT INTO ...

    COMMIT TRAN
END TRY
BEGIN CATCH
    EXECUTE usp_LogAndRethrowError
END CATCH

然后您的 LogAndRethrowError 可以回滚任何注定失败的事务,例如:

-- Make sure we are not in a live or 'doomed' transaction
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION

【讨论】:

@Nathan 如所述“您的 LogAndRethrowError 然后可以回滚任何注定失败的事务”。因此,您可以在 Catch 语句中添加 ROLLBACK TRAN(或让 SP 为您完成)。 不知何故没看到那部分答案。

以上是关于如果任何语句失败,将回滚的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

ROLLBACK语句只能针对未提交的事务进行回滚操作,已提交的事务是不能回滚的?

对mysql事务提交回滚的错误理解

sql 回滚语句

如果实现oracle中DDL语句的回滚

sql 事务自动回滚

我应该回滚失败的 SELECT 语句还是提交成功的语句?