我们有一个客户端应用程序在SQL Server 2005上运行一些SQL,如下所示:
BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;
它由一个长字符串命令发送。
如果其中一个插入失败,或者命令的任何部分失败,SQL Server是否会回滚该事务?如果它没有回滚,我是否必须发送第二个命令才能回滚?
我可以详细介绍我正在使用的api和语言,但我认为SQL Server应该对任何语言都做出相同的反应。
答案 0 :(得分:186)
您可以在事务之前放置set xact_abort on
,以确保sql在出错时自动回滚。
答案 1 :(得分:177)
您是正确的,因为整个交易将被回滚。您应该发出命令将其回滚。
您可以将其包装在TRY CATCH
块中,如下所示
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRAN --RollBack in case of Error
-- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH
答案 2 :(得分:28)
此处获取错误消息的代码与MSSQL Server 2016一起使用:
BEGIN TRY
BEGIN TRANSACTION
-- Do your stuff that might fail here
COMMIT
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRAN
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE @ErrorSeverity INT = ERROR_SEVERITY()
DECLARE @ErrorState INT = ERROR_STATE()
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH
答案 3 :(得分:21)
来自MDSN文章Controlling Transactions (Database Engine)。
如果批处理中发生运行时语句错误(例如违反约束),则数据库引擎中的默认行为是仅回滚生成错误的语句。您可以使用SET XACT_ABORT语句更改此行为。执行SET XACT_ABORT ON后,任何运行时语句错误都会导致当前事务的自动回滚。 SET XACT_ABORT不会影响编译错误,例如语法错误。有关更多信息,请参阅SET XACT_ABORT(Transact-SQL)。
在您的情况下,当任何插入失败时,它将回滚整个事务。
答案 4 :(得分:10)
如果其中一个插入失败,或者命令的任何部分失败,SQL服务器是否会回滚该事务?
不,它没有。
如果它没有回滚,我是否必须发送第二个命令才能回滚?
当然,您应该发出ROLLBACK
而不是COMMIT
。
如果要决定是提交还是回滚事务,则应从语句中删除COMMIT
句子,检查插入的结果,然后发出COMMIT
或{{1取决于检查的结果。