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

时间:2019-04-17 20:48:14

标签: sql-server tsql sql-server-2008 transactions rdbms

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

对于这些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   交易。

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

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

实际解释是什么?

2 个答案:

答案 0 :(得分:3)

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

在这种情况下,您得到的是批量中止,这将导致隐式回滚。该博客是有关SQL Server 2000错误处理的,但其中大部分仍然有效。

编辑:多进行一些挖掘,发现这一点专门提到了尝试创建一个已经存在的表的情况: http://www.sommarskog.se/error_handling/Part2.html#BatchTranAbort

答案 1 :(得分:2)

此Microsoft文章: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'的对象。”,@@TRANCOUNT是{ {1}},但是1XACT_STATE,因此SSMS中的错误消息指出:

  

消息3998,第16级,状态1,第1行是不可提交的交易,   在批次结束时检测到。交易被回滚。

下一个-1返回SELECT @@TRANCOUNT