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

问题描述 投票:3回答:2

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

在这些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相矛盾。

什么是实际的解释?

sql-server tsql sql-server-2008 transactions rdbms
2个回答
3
投票

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

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

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


2
投票

根据这篇微软文章: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

© www.soinside.com 2019 - 2024. All rights reserved.