c# - SQL 超时在不应该的时候过期

标签 c# sql asp.net sql-server sql-server-2008

我正在使用 SqlConnection 类并遇到命令超时到期的问题。

首先,我使用 SqlCommand 属性来设置命令超时,如下所示:

command.CommandTimeout = 300;

此外,我已确保将执行超时设置设置为 0,以确保 SQL 管理端不会出现超时。

这是我的代码:

using (SqlConnection conn = new SqlConnection(connection))
            {
                conn.Open();

                SqlCommand command = conn.CreateCommand();

                var transaction = conn.BeginTransaction("CourseLookupTransaction");

                command.Connection = conn;
                command.Transaction = transaction;
                command.CommandTimeout = 300;

                try
                {
                    command.CommandText = "TRUNCATE TABLE courses";
                    command.ExecuteNonQuery();

                    List<Course> courses = CourseHelper.GetAllCourses();

                    foreach (Course course in courses)
                    {
                        CourseHelper.InsertCourseLookupRecord(course);
                    }

                    transaction.Commit();
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                    Log.Error(string.Format("Unable to reload course lookup table: {0}", ex.Message));
                }
            }

我已经设置了日志记录并且可以在触发此函数后准确验证 30 秒,我在我的堆栈跟踪中收到以下错误消息:

Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

为了全面披露:InsertCourseLookupRecord() 在上面的 using 语句中找到 foreach,正在对同一个表执行另一个查询在同一个数据库中。这是它正在执行的查询:

INSERT INTO courses(courseid, contentid, name, code, description, url, metakeywords, metadescription)
VALUES(@courseid, @contentid, @name, @code, @description, @url, @metakeywords, @metadescription)"

此表中有 1400 多条记录。

我会证明任何帮助我解决这个问题的人都是至高无上的大巫师。

最佳答案

我相信正在发生的事情是您遇到了死锁情况,导致您在 InsertCourseLookupRecord() 函数中的查询失败。您没有将连接传递给 InsertCourseLookupRecord(),所以我假设您是在单独的连接中运行它。那么会发生什么:

  • 您开始了一笔交易。
  • 您截断了表格。
  • InsertCourseLookupRecord 启动另一个连接并尝试插入 数据到该表,但该表被锁定,因为你 事务尚未提交。
  • 函数 InsertCourseLookupRecord() 中的连接在为该连接定义的 30 秒超时值时超时。

您可以更改函数以接受命令对象作为参数并在函数内部使用它而不是创建新连接。这将成为事务的一部分,并将全部一起提交。

为此,将您的函数定义更改为:

public static int InsertCourseLookupRecord(string course, SqlCommand cmd)

从函数中取出所有连接代码,因为您将使用 cmd 对象。然后,当您准备好执行查询时:

myCommand.Parameters.Clear();  //need only if you're using command parameters
cmd.CommandText = "INSERT BLAH BLAH BLAH";
cmd.ExecuteNonQuery();

它将在相同的连接和事务上下文下运行。

你在你的 using block 中这样调用它:

CourseHelper.InsertCourseLookupRecord(course, command);

您也可以只获取 InsertCourseLookupRecord 中的代码并将其放入 for 循环中,然后在您的 using block 中重用命令对象,而根本不需要将它传递给函数。

关于c# - SQL 超时在不应该的时候过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31998696/

相关文章:

c# - 无法从 Entity Framework 中的模型代码生成数据库

c# - Linq to XML 根据属性值选择节点

python - 如何查询学生所在类(class)的文件?

c++ - 显示不同值的列数

c# - 将小数转换为整数

asp.net - 从 ASP.NET Core Controller 读取 docker-compose 环境变量

c# - 带参数的 LinkBut​​ton.OnClick 方法

c# - 管理 C# WPF 应用程序客户端 PC 文件夹中的 3000 个文件

c# - 使用 AutoFixture 对 Html 助手进行单元测试

mysql - 在 mySQL 中遇到 WHERE DATEDIFF 问题