2011-08-28 74 views
0

我们有一个助手类用于调用SQL Server上的存储过程。辅助功能如下所示:SQL连接问题

using (sqlCon = new SqlConnection(connectionString)) 
     { 

      // Create database command object 
      sqlCmd = sqlCon.CreateCommand(); 
      sqlCmd.CommandTimeout = commandTimeout; 

      // Set command text AND command type 
      sqlCmd.CommandText = procedureName; 
      sqlCmd.CommandType = CommandType.StoredProcedure; 

      // Set command parameters 
      if (paramCollection != null) 
      { 
       foreach (DatabaseParameter dbParam in paramCollection) 
       { 
        SqlParameter sqlParam = sqlCmd.Parameters.Add(dbParam.ParameterName, dbParam.ParameterType); 
        sqlParam.Direction = dbParam.ParameterDirection; 
        sqlParam.Value = dbParam.ParameterValue; 
        if (dbParam.ParameterSize != -1) 
         sqlParam.Size = dbParam.ParameterSize; 
        if (dbParam.ParamPrecision != -1) 
         sqlParam.Precision = (byte)dbParam.ParamPrecision; 
        if (dbParam.ParamScale != -1) 
         sqlParam.Scale = (byte)dbParam.ParamScale; 
       } 
      } 

      try 
      { 
       sqlCon.Open(); 
      } 
      catch 
      { 
       SqlConnection.ClearAllPools(); 
       sqlCon.Open(); 
      } 

      // Prepare command 
      sqlCmd.Prepare(); 

      // Execute the statement 
      sqlCmd.ExecuteNonQuery(); 

      if (sqlCmd.Parameters.Contains("@Result")) 
       return sqlCmd.Parameters["@Result"].Value; 
      else 
       return "Completed"; 
     } 

所以我们确保连接正确关闭。 该应用程序是一个多线程服务,所有线程都经常调用此方法。我们在调用上述帮助器方法的代码周围锁定(thisobject){}部分,以防止线程窃取其他每个连接。

connection.Open在ClearAllpools的try catch中清除断开的连接。

但是,我们间歇地通过一天的随机间隔获取以下错误列表。

连接的当前状态正在连接。

连接的当前状态是打开的。

这些错误每千次调用一次就会发生一次,因此很难排除故障。有人看到任何类似的东西或想法可能是错的吗?

+2

您的try-catch块看上去很腥 - 为什么要先清除连接池,然后*期望*连接现在能够打开? – BrokenGlass

回答

1

即使使用lock,我在处理多线程应用程序时也遇到过这些类型的错误。经过无数个小时的调试之后,我从未发现问题,最终在放弃之前尝试重新连接数次。迄今为止,我还没有看到再次出现错误。

int retries = 5; 
while(true) 
{ 
    try 
    { 
     DbCommand cmd = GetCommand(sql); 
     using(DbConnection conn = cmd.Connection) 
     { 
      conn.Open(); 
      // do stuff 
      break; 
     } 
    } 
    catch 
    { 
     Thread.Sleep(1000); 
     if(retries-- <= 0) 
     { 
      throw; 
     } 
    } 
} 
0

其他所有撇开,你有没有尝试有条件地进行,基于连接的State

using (sqlCon = new SqlConnection(connectionString)) 
{ 
    if (sqlCon.State == ConnectionState.Open) 
    { 
     .... 
    } 
} 
+0

我们已经尝试过,但仍然有相同的错误。从堆栈溢出的其他问题,我收集了可以断开连接的池中的连接,但没有改变它们的状态。所以即使连接状态= Open,它实际上是一个断开的连接。这就是为什么我们用ClearAllPools调用在try catch中打开连接的原因。 – Ghlouw

1

那么,我不能肯定地说为什么连接失败。但是什么错是你的catch块。你忽略了实际的错误,并用无用的替换它(你看到的那个)。

从不忽略异常。它们出于某种原因而被抛出,并且倾向于包含有关系统遇到的意外错误的有用信息。你很难找出问题,因为你没有看过它而扔掉有用的信息。

您看到的错误来自您的catch块中的代码。这段代码本质上是试图去做那些失败的确切事情,但方式稍有不同。你需要记录你的错误,以便你能够找出失败的原因,并首先到达catch块。

try/catch块的一个很好的经验法则是,如果您准备好句柄例外,那么您应该只捕获异常。在这里你根本没有处理它,所以除非你这样做,否则你应该完全删除try/catch。让异常冒泡到可以处理的地方。或者,将catch块中的代码替换为一些错误日志记录,并以有用和有意义的方式退出代码块(向调用代码块返回一个错误,并在其中引入捕获异常的自定义异常等)。

+0

你说得对,那不是最有用的try catch块,而且当人们使用try catch没有很好的理由时,我也讨厌它。上面的代码实际上是一个更大的尝试捕获的一部分,适当的日志记录和处理,但围绕打开连接的小尝试捕获是绝望措施的结果。 :) – Ghlouw