在C#中的TransactionScope中出现超时问题

时间:2013-05-08 19:28:33

标签: c# sql-server transactionscope timeoutexception

我有一个适用于较小数据集的插入方法,但是一旦数据集超出一定大小,该方法就会超时,无论我在初始事务范围中设置了什么。

代码中的insert方法使用简单存储的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中设置的超时“在我们的程序配置文件中设置的连接超时值,我只能修改以用于测试但不能更改其中的任何值),但是任何大于它的东西都会崩溃。

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

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

编辑:

根据请求,我添加了一个最终由nameDB.insert方法调用的插入方法的示例(删除了Fluff,请注意实际的insert方法实际上是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;
        }

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

交易不应该运行很长时间! 这是设计在SQL Server等底层平台上。超时就像安全阀;打开它们可能会导致系统崩溃。

Inserts花费这么多时间的原因是因为你为每一行执行查询。这意味着每一行:

  1. 客户端必须将命令发送到SQL Server
  2. SQL Server执行它
  3. SQL Server将结果返回给客户端
  4. 如果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();      
             }
        }
    }