【问题标题】:Issue with timeout within TransactionScope in C#C# TransactionScope 中的超时问题
【发布时间】:2013-05-08 19:28:33
【问题描述】:

我有一个插入方法可以很好地处理较小的数据集,但是一旦数据集超过一定大小,无论我在初始事务范围中设置什么,该方法都会超时。

代码中的插入方法使用简单的存储 sql 过程,通过“ExecuteNonQuery”调用

我的代码看起来像这样(去除了绒毛):

     public void method()
     {

     using (TransactionScope testScope = new TransactionScope(TransactionScopeOption.Required, new System.TimeSpan(1, 25, 0)))
                    {

                    timeDB.insert(var.time);

                    codeDB.insert(var.code);

                    foreach (variable var in listOfVariables)
                            {

                            nameDB.insert(var.value);

                            }

                    testScope.Complete();
                    }   
    }

我认为问题与命令超时而不是范围超时有关,因为代码适用于较小的数据集....如果是这种情况,是否有任何方法可以更改命令超时不修改 machine.config(或任何其他 .config 文件,我严格禁止修改它们,因为更改值会弄乱程序的其余部分)

如果问题不是特定命令超时,是什么原因造成的?就像我说的那样,代码在 8000-15000 次插入之间的任何地方都可以正常工作(取决于我们的 ConnectionString “连接超时值在我们的程序配置文件中设置的超时值,我只能出于测试目的进行修改,但不能更改其中的任何值),但是任何比这更大的东西都会崩溃。

我也确定这绝对不是范围超时值,因为大约几分钟后任务超时,没有在 transactionscope 中设置的 1 小时 25 分钟附近

提前感谢您抽出宝贵时间帮助我解决此问题。

编辑:

根据要求,我添加了一个插入方法的示例,该方法最终由 nameDB.insert 方法调用(Fluff 已删除,请注意,实际的插入方法实际上是 NameDB.insert 方法的子方法,并且实际的循环在 nameDB.insert 方法中。我只是使用 NameDB....等来减少绒毛。)

  public Int32 Insert(Hashtable serData, DataDO data)
        {
            int numAffected = 0;

            IDataParameter[] parameters = 
                    {                       
                        this.Helper.GetParameter("@Text", data.Text),
                        this.Helper.GetParameter("@CreationDt", ((data.CreationDate == DateTime.MinValue) 
                        ? Convert.DBNull : data.CreationDate)),                     
                        this.Helper.GetParameter("@TypeId", data.TypeId),                       
                        this.Helper.GetParameter("@KeyId", DbType.Int32, 4, ParameterDirection.Output)
                    };

            numAffected = this.Helper.ExecuteNonQuery(this.ConnectionString, "InsertData", parameters);

            if (numAffected > 0)
                return Convert.ToInt32(parameters[parameters.Length - 1].Value);

            return 0;
        }

【问题讨论】:

  • 正如 Oana 所说,您需要 DbCommand 对象的 CommandTimeout 属性。您能否提供有关示例中 timeDB 和 codeDB 的更多信息?
  • 如果您的交易将转到 DTC,请注意 DTC 的最大超时时间非常短 - 有一个很好的理由:您应该将交易保持很长时间 -尤其是“可序列化”的。
  • 我已经编辑了帖子以添加插入方法,因为它对于 cmets 来说太长了。感谢您的帮助。

标签: c# sql-server transactionscope timeoutexception


【解决方案1】:

我认为您也可以在代码中设置命令超时:DBCommand,如果您使用的是命令。并且 DbCommand 不继承自事务范围或连接字符串,因此您必须手动设置它。

【讨论】:

    【解决方案2】:

    事务不应长时间运行! 这是设计使然,在 SQL Server 等底层平台中。超时就像安全阀;过多打开它们可能会导致系统崩溃。

    插入需要这么多时间的原因是您对每一行执行查询。这意味着对于每一行:

    1. 客户端必须将命令发送到 SQL 服务器
    2. SQL Server 执行它
    3. SQL Server 将结果返回给客户端

    如果 SQL 连接通过网络,则每个循环的延迟会更长。

    推荐的解决方案是批量发送插入。有很多方法可以做到这一点,根据您可以投入重构的时间量,它可以来自简单的动态 SQL 字符串构建器 SQLBulkLoad 或使用对象关系映射 (ORM) 工具,例如实体框架 (EF)或支持批量更新的 nHibernate。

    使用 ORM,你的代码会变成这样:

    public void method()
    {
         using(MyDatabase db = new MyDatabase())
         {
             timeDB.insert(var.time);
             codeDB.insert(var.code);
    
             foreach (variable var in listOfVariables)
             {
                 nameDB.insert(var.value);
             }
    
             using (TransactionScope testScope = new TransactionScope())
             {
                  db.SaveChanges();
                  testScope.Complete();      
             }
        }
    }
    

    【讨论】:

    • 您好迈克尔,感谢您的回复。我尝试了您的建议,但仍然超时。如果我发现什么,会告诉你的。谢谢!
    • 创建 SQL 脚本,将它们包装在一个大事务中,然后直接在 SQL 查询分析器(或您正在使用的数据库的相应工具)中运行它。它仍然超时吗?如果没有,需要多长时间才能完成?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多