SQL Server连接超时和使用带有命令和连接对象的语句

时间:2016-02-29 20:34:49

标签: c# sql sql-server connection-timeout

请在回复之前阅读整个问题。我道歉,我似乎永远不会写简短的问题......

我正在支持一个C#内部网络应用程序,该应用程序可以访问在Windows Small Business Server 2011 SP1上运行的SQL Server 2008 R2。

我们最近收到了很多SQL超时,这是一个例外情况:

  

System.Web.HttpUnhandledException:类型' System.Web.HttpUnhandledException'的异常。被扔了。 ---> System.InvalidOperationException:超时已过期。从池中获取连接之前经过的超时时间。这可能是因为所有池连接都在使用中并且达到了最大池大小。   在System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)   在System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection,DbConnectionFactory connectionFactory)   在System.Data.SqlClient.SqlConnection.Open()

我检查了一些事情,其中​​一个是代码处理连接和关闭连接的方式。我已经在其他线程中读到,使用带有连接的Using语句就足够了,因为它... ...最后将连接创建包装起来并最终将连接处理调用放在finally"中。即使发生异常,连接也会关闭。

所以,我同意并且已经使用了这种方法多年。其他人建议显式关闭连接,即使在连接中使用Using语句也是如此。我认为这将是多余的......

然而,我的问题是关于命令对象。其他人为这个应用程序编写了一个大型的db方法库,他们(在所有的db方法中)使用语句在SqlConnection对象之前声明了SqlCommand对象。他们还在连接using语句之前将连接对象分配给命令对象。

更好的做法是在连接using语句中声明和使用命令对象,并且可以通过其他方式执行此操作导致sql连接超时(除了sql连接超时的其他原因)?以此代码为例:

    public Musician GetMusician(int recordId)
    {
        Musician objMusician = null;
        SqlConnection con = new SqlConnection(_connectionString);
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = con;
        cmd.CommandText = "selectMusician";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@id", recordId);

        using (con)
        {
            con.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            if (reader.HasRows)
            {
                reader.Read();
                objMusician = new Musician((int)reader["id"]);
                objMusician.Name = (string)reader["name"];
            }
        }

        if objMusician != null)
        {
            objMusician.Albums = Albums.GetAlbums((int)objMusician.ID);
            objMusician.Tours = Tours.GetTours((int)objMusician.ID);
            objMusician.Interviews = Interviews.GetInterviews((int)objMusician.ID);
        }
        return objMusician;
    }

还要知道调用页面已经尝试捕获它们,并且它是将错误记录到我们的日志记录数据库的页面。我们让异常冒泡到页面上的调用方法,然后在那里处理。

3 个答案:

答案 0 :(得分:0)

完成后,您应该明确关闭连接。您永远不会关闭任何连接,因此在您达到连接池限制之后,您将获得错误,直到您手动回收池或它自行循环。在使用块内移动属性赋值块并执行con.Close(); cmd.Dispose();在回到你的objMusician之前:

using (con)
{
    con.Open();
    SqlDataReader reader = cmd.ExecuteReader();
    if (reader.HasRows)
    {
        reader.Read();
        objMusician = new Musician((int)reader["id"]);
        objMusician.Name = (string)reader["name"];
    }

    if objMusician != null)
    {
        objMusician.Albums = Albums.GetAlbums((int)objMusician.ID);
        objMusician.Tours = Tours.GetTours((int)objMusician.ID);
        objMusician.Interviews = Interviews.GetInterviews((int)objMusician.ID);
    }

    con.Close();
    cmd.Dispose();        

    return objMusician;
}

答案 1 :(得分:0)

不知道它是否有助于解决您的超时问题,但我总是按照以下方式构建我的代码并且没有遇到此问题:

using(var cmd = new SqlCommand())
{
    using(var con = new SqlConnection(ConnectionString))
    {
        con.Open();
        cmd.Connection = con;
        cmd.CommandText = "selectMusician";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@id", recordId);
        ...
    }
}

只是在MSDN上阅读,它说"当您使用完组件后调用Dispose。 Dispose方法使Component处于不可用状态。在调用Dispose之后,必须释放对Component的所有引用,以便垃圾收集器可以回收Component占用的内存。"这意味着为了让GC立即收集连接,您必须在处理命令之前处置连接,否则连接会一直挂起,直到GC到处调用Finalize为止。

答案 2 :(得分:0)

按如下方式重构您的方法。您可能遇到数据阅读器引用连接但尚未处理的情况。

public Musician GetMusician(int recordId)
{
    Musician objMusician = null;

    using(SqlConnection con = new SqlConnection(_connectionString))
    {
        con.Open();
        using (SqlCommand cmd = new SqlCommand())
        {
            cmd.Connection = con;
            cmd.CommandText = "selectMusician";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@id", recordId);

            using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
            {
                if (reader.HasRows)
                {
                    reader.Read();
                    objMusician = new Musician((int) reader["id"]);
                    objMusician.Name = (string) reader["name"];
                }

                if objMusician != null)
                {
                    objMusician.Albums = Albums.GetAlbums((int)objMusician.ID);
                    objMusician.Tours = Tours.GetTours((int)objMusician.ID);
                    objMusician.Interviews = Interviews.GetInterviews((int)objMusician.ID);
                }
            }
        }

        return objMusician;
    }
}