SQL 错误“在批处理结束时检测到不可提交的事务”,数据库上没有事务

Posted

技术标签:

【中文标题】SQL 错误“在批处理结束时检测到不可提交的事务”,数据库上没有事务【英文标题】:SQL Error "uncommittable transaction is detected at the end of batch" without transactions on db 【发布时间】:2014-07-16 12:14:49 【问题描述】:

我在代码的不同点面临以下问题。 调用存储过程后,从 DB (SQL Server) 返回 SqlException,并显示消息“在批处理结束时检测到不可提交的事务。事务已回滚”。存储过程结构如下:

USE [EXAMPLE_DB]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_ExampleStoredProcedure]
@Parameter INT, @AnotherParameter INT

AS
BEGIN
    BEGIN TRY

    SET NOCOUNT ON;


    DECLARE @Variable INT;
    DECLARE @AnotherVariable CHAR;
    DECLARE @ErrMsg VARCHAR;

    SET @ErrMsg = '';

    /*Doing Some Stuff Here (Select, IF-THEN, etc...)

            /* I call another stored procedure */   
            EXECUTE [dbo].[sp_SecondStoredProcedure] 
                       @Param = 'Blabla'
                      ,@Param2 = 'BlaBlaBla'


            /*Here I handle some custom output parameters from second stored                           
                     procedure to handle errors */



                    /* Other stuff here */

END TRY

BEGIN CATCH    
        SET @CustomExitCode = 'XXXXX';
        SET @ErrMsg = (SELECT ERROR_MESSAGE()); 
END CATCH;

END

如您所见,在存储过程内部没有事务处理。 我使用 TransactionScope 类处理事务代码端(C#),在事务范围内调用各种存储过程,包括上面的一个(这是失败的那个)。

问题是:如果我没有事务 SQL 端,但只有一个 try-catch 块,所有事务处理都在代码上执行,为什么 SQL 会谈论 Uncommitable Transaction?

我已经在网上搜索了很多关于 Uncommittable Transaction 错误的资料,但实际上到处都有 SQL 端的事务处理。

我希望我以一种可以理解的方式解释了这个问题。 我显然可以提供任何进一步的信息。

非常感谢您的帮助!

干杯, 加布里埃尔

【问题讨论】:

显示你的 c# 调用代码.... 【参考方案1】:

如果您在“代码”中启动事务,那么该事务也将对过程可见。不然怎么会是真正的交易呢?

当您将事务与 try catch 结合使用时,出现大量错误(尤其是使用 XACT_ABORT ON 时)会导致“无法提交的事务错误”,请参阅 XACT_STATE 文档。

发生错误时,您必须对事务进行一些处理,如果不这样做,它会在离开过程时自动回滚。

出于这些和其他原因,我们通常避免将尝试捕获与事务一起使用。由于您使用的是 C# 代码,您不妨将 try catch 移至应用程序部分,并将事务处理与 XACT_ABORT ON 保持在一起,这意味着它将在出错时回滚

【讨论】:

【参考方案2】:

将所有操作在 TRY BLOCK 中包装在 Transaction 中,让 sql server 为您处理它,而不是您在应用程序中处理它。在 Try Block 中显式 BEGIN TRAN 和 COMMIT Trans,如果在此事务期间出现任何问题,则回滚它。

我会做类似......

ALTER PROCEDURE [dbo].[sp_ExampleStoredProcedure]
@Parameter INT, @AnotherParameter INT
AS
BEGIN
    SET NOCOUNT ON;
 BEGIN TRY
    DECLARE @Variable INT;
    DECLARE @AnotherVariable CHAR;
    DECLARE @ErrMsg VARCHAR;

    SET @ErrMsg = '';
BEGIN TRANSACTION;      --<-- Begin here 

    /*Doing Some Stuff Here (Select, IF-THEN, etc...)*/

            /* I call another stored procedure */   
            EXECUTE [dbo].[sp_SecondStoredProcedure] 
                       @Param = 'Blabla'
                      ,@Param2 = 'BlaBlaBla'
            /*Here I handle some custom output parameters from second stored                           
                     procedure to handle errors */

                    /* Other stuff here */
COMMIT TRANSACTION;     --<-- Commit here if nothing gone wrong

END TRY

BEGIN CATCH    
  IF (@@TRANCOUNT > 0)
   BEGIN
      ROLLBACK TRANSACTION;   --<-- Rollback if something went wrong
   END

           /*Other error logging here*/
        SELECT @CustomExitCode = 'XXXXX', @ErrMsg = ERROR_MESSAGE(); 
END CATCH;

END

【讨论】:

感谢您的回答 M.Ali!不幸的是,代码是企业应用程序的一部分,不能修改事务处理。我很想了解它为什么会这样。例如,SQL 事务引擎和 C# 事务引擎之间的任何交互?无论如何,非常感谢! 你写的东西并不总是一个好的解决方案(M.Ali。)如果有多个表要处理,那么最好在所有表都更新后应用程序进行提交/正确插入。 (恕我直言!) C# 事务引擎只不过是 SQL Server 事务的包装器。这不像 C# 有自己的回滚 SQL Server 代码的方式。当您在 C# 中创建 TransactionScope 时,它​​会模拟框架中某处的“BEGIN TRAN”,当您超出范围时会模拟“COMMIT TRAN”,因此事务的行为是 SQL Server 的“原生”跨度>

以上是关于SQL 错误“在批处理结束时检测到不可提交的事务”,数据库上没有事务的主要内容,如果未能解决你的问题,请参考以下文章

设置 xact_abort 并尝试一起捕捉

我的 SQL 错误:错误 1064:您的 SQL 语法有错误;

求解!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!SQL Server 2012 出现以下错误:

ORACLE:错误错误(6,3):PL/SQL:SQL 语句被忽略和错误(8,3):PL/SQL:ORA-00933:SQL 命令未在过程中正确结束

oracle如何检查sql语法错误

SQL 错误 1064:您的 SQL 语法有错误