【问题标题】:Why doesn't TransactionScope start a transaction for my following SQL commands为什么 TransactionScope 不为我的以下 SQL 命令启动事务
【发布时间】:2020-04-26 11:54:37
【问题描述】:

我在 ASP.NET 操作开始时为 TransactionScope 设置了一个 using 块。在某个地方,我使用该块执行一个函数,该函数既为SqlCommand 创建一个使用块,又为我的SqlConnection 创建一个使用块。

命令和连接的块在函数被重用时打开和关闭,但都带有TransactionScope using 块。最终我打电话给scope.Complete(),当离开TransactionScope using 块时,我得到一个异常,说没有启动可以提交的事务。在调试中,我发现实际上所有数据库调用都只是在没有事务的情况下发生。

根据文档,TransactionScope 的生成似乎应该是事务的生成,或者,至少在我第一次打开任何数据库连接时,事务应该开始,因为它是 w/i 事务范围块。然而事实并非如此,我不确定为什么会这样。

实际上,我曾经一度可以正常工作,然后突然之间,它就无法正常工作了。所以是我做的一些事情导致了它,但我不知道它是什么,因为它实施的部分很久以前就完成了。

这里有一些代码:

启动事务作用域

using (TransactionScope transactionScope = new TransactionScope())
{
    try
    {
        LegacyDataManager.Start();

        //*******************Replace W/ Controller Logic*********************
        ViewBag.Message = "Finish";
        ...
        ...
        ...
        LegacyDataManager.Commit();
        transactionScope.Complete();
    }
    finally
    {
        LegacyDataManager.Stop();
    }
}

调用执行数据库更新的代码

var theApproval = LegacyDataManager.PrepareForUpdate(Constants.ObjectApproval, row["objectInstance"].ToString(), row["sourceServer"].ToString());
                                    theApproval.write("approvalaction", Request.Form[val].ToString().Substring(0, 1));
                                    theApproval.write("approvaldate", Data_Legacy.getAodDateTimeNow());
                                    theApproval.saveObject();

数据库查询执行

Data.executeSP("sp_Object_InsertData", SearchNew.generateSQLParameterString("ObjectType", "ObjectInstance", "Parameter", "ParameterValue", "SourceServer"),
                                                SearchNew.generateSQLParameterString(
                                                ObjectType,
                                                ObjectInstance.ToString(),
                                                theNametext,
                                                Regex.Replace(thetheVal, @"\'", "\'\'").Trim(),
                                                SourceServer));

public static DataTable executeSP(string storedProc, SqlParameter[] parms = null, bool gatherParams = true, int commandTimeout = 0)
{
    using (SqlCommand cmd = new SqlCommand())
    {
        if (commandTimeout != 0)
        {
            cmd.CommandTimeout = commandTimeout;
        }

        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = storedProc;

        handleParameters(cmd.Parameters, storedProc, parms, gatherParams);

        using (SqlConnection conn = Data.getConnection("AOD"))
        {
            if (conn.State != ConnectionState.Open) 
                conn.Open();

            cmd.Connection = conn;

            var da = new SqlDataAdapter();
            var dt = new DataTable();
            da.SelectCommand = cmd;
            da.Fill(dt);

            return dt;
        }
    }
}

提前感谢您的任何建议。

好消息是它可以被删除,但坏消息是它创建了一个烦人的编程环境,其中该系统所基于的 XML 数据文件在错误期间不会更新,但更新的 SQL 数据会被镜像out to 被保留了……不要问为什么会这样……就是这样。

【问题讨论】:

    标签: asp.net .net sql-server


    【解决方案1】:

    显然我在运行存储过程的函数周围添加了一个 try/catch 块,因为传入的数据有时需要该函数,有时不需要(因此失败,因此 try catch)。不幸的是,当 db 调用失败时,与 TransactionScope 关联的事务被删除,try catch 使程序继续运行。

    在确定是否执行存储过程之前,我删除了 try catch 块并将其替换为检查传递给函数的数据,现在它再次正常运行。

    TL;DR - 使用 transactionScope 检查是否有任何数据库调用失败,因为它可能导致事务丢弃。

    【讨论】:

    • 您的 TL;DR 不正确 - TransactionScope 中的 try..catch 没有任何问题。说应该避免使用它们是不准确的,因为有充分的理由使用它们。
    • @Fermin 当潜在的可怕问题完全与使用 try catch 直接相关时,你怎么能这么说?
    • TransactionScope 中使用try..catch 是完全有效的,这就是为什么我说这是不正确的。您的一个具体问题与您如何实施它们有关。作为比较,我在将字符串转换为 DateTime 时遇到了问题,但我不建议使用 TL;DR: Try to avoid DateTime when using strings
    • 我已经考虑过这一点,现在认为问题与 try catch 中的内容有关,而不是 try catch 本身。我在函数中执行了一个存储过程,该函数包含 w/i try catch 块,并且存储过程由于传递给它的数据而失败。我假设数据库端的错误与 transactionScope 的事务丢失之间存在一些相关性。不管 try catch 允许它继续按预期进行。我将根据实际情况更改原始消息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 2014-07-17
    • 2017-02-13
    • 2017-04-26
    • 1970-01-01
    相关资源
    最近更新 更多