C#中TransactionScope超时问题

3

我有一个插入方法,对于较小的数据集可以正常工作,但一旦数据集超过一定大小,无论我在初始事务范围中设置什么,该方法都会超时。

代码中的插入方法使用简单的存储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个插入之间运行良好(取决于我们程序配置文件中设置的连接超时值,我只能为测试目的进行修改,但不能更改其中的任何值),但大于此数量后程序就崩溃了。
我确定这绝对不是范围超时值,因为任务在几分钟后超时,远未达到事务范围设置的1小时25分钟。
非常感谢您花时间帮助我解决这个问题。
编辑:
按照要求,我添加了一个insert方法的示例,最终由nameDB.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;
        }

正如Oana所说,您需要使用DbCommand对象的CommandTimeout属性。您能否提供有关示例中timeDB和codeDB是什么的更多信息? - The other other Alan
如果您的交易要发送到DTC,请注意DTC的最大超时时间非常短 - 这是有很好的原因的:您不应该将事务保持打开太长时间 - 尤其是“可串行化”的事务。 - Marc Gravell
我已经编辑了帖子,添加了插入方法,因为它太长了,无法在评论中展示。谢谢你的帮助。 - A.D
2个回答

0

事务不应该运行很长时间! 这是设计上的考虑,如 SQL Server 等底层平台。超时像安全阀门一样;将其过度打开可能会导致系统崩溃。

插入操作需要花费很长时间的原因是因为您为每行执行查询。这意味着对于每一行:

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

如果 SQL 连接通过网络进行,则每个循环的延迟时间甚至更长。

推荐的解决方案是批量发送插入操作。有许多方法可以实现它,取决于您可以投入多少时间进行重构,可以使用简单的动态 SQL 字符串生成器、SQLBulkLoad 或使用支持批处理更新的对象关系映射(ORM)工具,如 Entity Framework (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();      
         }
    }
}

你好,Michael,感谢您的回复。我尝试了您的建议,但仍然超时。如果我发现任何信息,我会让您知道。谢谢! - A.D
创建SQL脚本,将它们包装在一个大事务中,并直接在SQL查询分析器(或您正在使用的数据库的相应工具)中运行。它是否仍然超时?如果没有,完成需要多长时间? - Michael

0

我认为你也可以在代码中设置命令超时时间:DBCommand,如果你正在使用一个命令。而且DbCommand没有继承事务范围或连接字符串,所以你必须手动设置它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接