2013-06-19 32 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对象或任何东西? –

相关问题