簡體   English   中英

SQL Timeout在不應該的時候過期

[英]SQL Timeout Expired When It Shouldn't

我正在使用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.

為了完全公開:在上面的using語句foreach中找到InsertCourseLookupRecord() ,正在對同一個數據庫中的同一個表執行另一個查詢。 這是它正在執行的查詢:

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();

它將在相同的連接和事務上下文中運行。

你在你的使用塊中這樣稱呼它:

CourseHelper.InsertCourseLookupRecord(course, command);

您也可以只使用InsertCourseLookupRecord中的代碼並將其放在for循環中,然后在using塊中重用命令對象,而無需將其傳遞給函數。

因為您使用了兩個單獨的SqlConnection對象,所以由於您在外部代碼中啟動的SqlTransaction而導致自我死鎖。 InsertCourseLookupReacord的查詢以及GetAllCourses的查詢被尚未提交的TRUNCATE TABLE courses調用阻止。 他們等待300秒,然后提交截斷。

你有幾個選擇。

  1. 將SqlConnection和SqlTransaction傳遞給GetAllCoursesInsertCourseLookupRecord以便它們可以成為同一事務的一部分。
  2. 通過刪除SqlTransaction並使用System.Transaction.TransactionScope來使用“環境事務”。 這會導致打開到服務器的所有連接都共享一個事務。 這可能會導致維護問題,具體取決於查詢正在執行的操作,因為它可能需要調用可能在某些計算機上禁用的分布式事務處理協調器 (從您顯示的內容看起來需要DTC,因為您有兩個打開的連接同時)。

最好的選擇是嘗試更改代碼以執行選項1,但如果您不能執行選項2。

取自文檔

對上下文連接執行命令時,CommandTimeout無效(在連接字符串中使用“context connection = true”打開SqlConnection)

請檢查您的連接字符串,這是我能想到的唯一可能性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM