当INSERT INTO失败时,为什么我的事务会自动回滚?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当INSERT INTO失败时,为什么我的事务会自动回滚?相关的知识,希望对你有一定的参考价值。

令人惊讶的是,我找不到任何有关此问题的相关解释或文档。

在这些SQL语句的情况下:

SELECT 1 AS Test INTO #tmpTest    
BEGIN TRAN    
SELECT 1 AS Test INTO #tmpTest    
ROLLBACK TRAN

当逐个执行时,第3行的SELECT ... INTO失败,正如预期的那样,带有消息 -

数据库中已经有一个名为“#tmpTest”的对象。

但是,之后,第4行中的ROLLBACK语句失败:

ROLLBACK TRANSACTION请求没有相应的BEGIN TRANSACTION。

即使交易从第2行成功地做了BEGIN

我见过SQL Server - transactions roll back on error?,但答案不适用于此,因为默认的xact_abortoff。此外,answer from Quassnoianswer by Raj More相矛盾。

什么是实际的解释?

答案

请参阅http://www.sommarskog.se/error-handling-I.html

你得到的是这种情况下的批量堕胎导致隐式回滚。该博客是关于SQL Server 2000错误处理,但大多数仍然有效。

编辑:再挖掘一下,发现这个特别提到了尝试创建一个已经存在的表的情况:http://www.sommarskog.se/error_handling/Part2.html#BatchTranAbort

另一答案

根据这篇微软文章:XACT_STATE (Transact-SQL)

(...)发生错误导致交易被归类为不可提交的交易。请求无法提交事务或回滚到保存点;它只能请求完全回滚事务。

我先跑这个:

SELECT 1 AS Test INTO #tmpTest    
SELECT @@TRANCOUNT, XACT_STATE()
BEGIN TRAN    
SELECT @@TRANCOUNT, XACT_STATE()

然后:

BEGIN TRY
    SELECT 1 AS Test INTO #tmpTest    
END TRY
BEGIN CATCH
    SELECT @@ERROR, ERROR_MESSAGE()
    SELECT @@TRANCOUNT, XACT_STATE()
END CATCH

SELECT块中的CATCH返回:“数据库中已经有一个名为'#tmpTest'的对象。”,@@TRANCOUNT1,但XACT_STATE-1,因此SSMS中的错误消息指出:

消息3998,级别16,状态1,行1在批处理结束时检测到不可提交的事务。该事务被回滚。

下一个SELECT @@TRANCOUNT返回0

以上是关于当INSERT INTO失败时,为什么我的事务会自动回滚?的主要内容,如果未能解决你的问题,请参考以下文章

INSERT INTO MySQL 语句失败

MySql insert into 失败?

INSERT INTO 因 node-mysql 而失败

insert into的用法

mysqli事务在insert失败时无法回滚

INSERT INTO 查询不能包含多值字段