2013-06-19 61 views
2

我有一個運行一些ExecuteNonQuery命令的循環。 偶爾它返回的錯誤信息:隨機獲取ExecuteNonQuery需要一個開放且可用的連接

ExecuteNonQuery requires an open and available connection. The connections 
current state is closed. 

這裏是我的代碼:

private void MyTimerEventHandler(object src, ElapsedEventArgs a) 
{ 
    sqlCon = new SqlConnection("server=" + appConfig.sqlServer + ";Trusted_Connection=yes;database=testdb;connection timeout=30;"); 
    sqlCon.Open(); 

    foreach (TagManager tm in tagManagerList) 
    { 
     foreach (Tag tag in tm.getTags()) 
     { 
      SqlCommand insCmd = new SqlCommand("INSERT INTO tag_values (tag_id, value, time) Values (@tagId, @tagValue, @tagTime);", sqlCon); 
      insCmd.Parameters.Add(new SqlParameter("@tagId", tag.tagNameId)); 
      insCmd.Parameters.Add(new SqlParameter("@tagValue", tag.value)); 
      insCmd.Parameters.Add(new SqlParameter("@tagTime", tag.time)); 

      insCmd.ExecuteNonQuery(); 
     } 
    } 

    sqlCon.Close(); 
} 

此代碼執行運行每15秒一個Timer的事件處理程序。如果這有什麼區別的話,定時器會保持活躍狀態​​GC.KeepAlive()

+1

該代碼暗示sqlCon是該類的一個字段。也許在30秒的超時時間內,你有一個新的調用,在先前的調用完成時開始運行,而舊的調用在中途關閉連接? – Mikeb

+0

你釘了它。這是在15秒計時器上觸發的,所以如果第一次調用在第二次觸發時仍然在運行,那麼第一次調用會在第二次調用時關閉連接,導致此問題。這就是爲什麼你不像這樣共享連接對象的原因。 –

+0

請改用(var sqlCon = new SqlConnection(...)){}來代替。如果sqlConn.Open()和sqlConn.Close()之間發生異常,連接將不會正確關閉。 –

回答

2

每個定時器回調創建一個新的連接對象:

private void MyTimerEventHandler(object src, ElapsedEventArgs a) 
{ 
     SqlConnection sqlCon = new SqlConnection([...] 

它通常是一個壞主意重用連接。在你的情況下,如果該連接正在另一個線程中使用,則可能會遇到競爭條件。 創建新連接不應影響從連接池中提取的性能。

+0

每個插入命令的新連接對象?我每15秒插入600行,這個數字可能會在未來增加。這是個好主意嗎? –

+0

我不同意你的說法,即在循環中創建連接是個好主意。我的經驗是這是一個可怕的想法。但我認同比賽條件,尤其是考慮到@邁克在主要職位上的評論。如果邁克是對的,集合是你的敵人。 – DonBoitnott

+0

是的,從連接池中檢索數據庫連接,以便重用現有數據庫連接(如果可用)。 – fcuesta

0

可以檢查你的連接仍處於打開狀態之前執行的查詢

if (sqlCon.State == System.Data.ConnectionState.Open) 
        { 
         insCmd.ExecuteNonQuery(); 
        } 
        else 
        { 
         sqlCon.Open(); 
         insCmd.ExecuteNonQuery(); 
        } 
       } 
+0

爲什麼我的連接會關閉?在定時事件運行時,我需要可靠地插入數據的每一行,每次運行時都要插入一行。 –

+0

嗯,也許你可以添加一個嘗試陰道,並採取錯誤的上升,也許一個錯誤插入,你不管理或其他情況下,也許是連接超時...現在嘗試添加一個嘗試cath和測試..並讓我們知道 –

0

您不用通過使用StringBuilder來準備插入語句,並將其作爲文本傳遞給SQL命令,以便通過SQL SERVER發送一次來插入。在這種情況下,對於所有600個循環,您將需要連接到DB一次。只是一個想法

+0

通過stringbuilder建立一個sql查詢聽起來像一個可怕的想法。你確定沒有BatchInsert對象或任何東西? –

相關問題