在C#中打开/关闭SqlConnection的最佳方法是什么?

4

我想知道在使用 Sql Server 2008R2 Express Edition 数据库时,打开 SqlConnection 的最佳方法是什么。由于这个版本的 Sql 存在 RAM 使用和 CPU 使用的限制,因此我们必须采用最佳方案来打开 SqlConnection

目前,我正在检查每个方法的开始和结束时的连接情况。以下是一个示例。

   private void CheckValidId(string Id)
    {
        CheckConnectionStatus();

        try
        {
            sqlConnection.Open();
            sqlCommand = new SqlCommand("select * from ValidId where id=@id", sqlConnection);
            sqlCommand.Parameters.AddWithValue("@id", Id);
            sqlDataReader = sqlCommand.ExecuteReader();
            While (sqlDataReader.Read())
            {
               string Test = sqlDataReader["Id"].toString();
               MessageBox.Show("Value of Id : " , Test);
            }
        }
        catch (Exception exp)
        {
            MessageBox.Show(exp.Message.ToString(), "Exception in CheckValidId");
        }
        finally
        {
            CheckConnectionStatus();
        }
    }

这里是 CheckConnectionStatus 方法。
    private void CheckConnectionStatus()
    {
        if (sqlConnection.State == ConnectionState.Open)
        {
            sqlConnection.Close();
        }
    }

如何最好地执行此操作。

谢谢。


以下是您需要的两个正确答案,使用using语句的原因是它是可处理的。当完成时,它将自动关闭连接。 - Simon Price
@SimonPrice 谢谢你 - Jaa Zaib
3个回答

6

只需使用using,因为它会在完成后处理连接。

 using(SqlConnection conn = new SqlConnection("Connection string")){
  //do sql stuff
  conn.Open(); 
  //etc etc
  conn.Close();
 }

感谢您的热心建议。 - Jaa Zaib
5
注意:conn.Close(); 是可选的,因为当您处理连接时,它会自动关闭连接。 - FakeCaleb

5

您需要使用一次性模式,以确保所有内容都被正确关闭和处理:

var query = "select * from ValidId where id=@id";

using (var conn = new System.Data.SqlClient.SqlConnection(usingConnectionString))
using (var command = new System.Data.SqlClient.SqlCommand(query, conn))
{
    command.Parameters.Add("@id", SqlDbType.Int).Value = Id;
    conn.Open;

    using (var reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            string Test = reader["Id"].ToString();
        }
    }

    command.Parameters.Clear();
}

不需要检查连接状态;在被处理时它会自动关闭。

需要注意的一点是:最佳实践是显式指定参数数据类型。在您的情况下,我假设使用了 SqlDbType.Int,但您可以更改为实际值。

另外需要注意的是:在读取器循环中不要做太多事情。您需要构建集合或其他内容并尽快离开。连接打开的时间越短,越好。这是因为您可能会对数据库中的某些行持有读锁,从而影响其他用户和其应用程序。


1
除非您使用Data Adapter的Fill()方法自动打开(和关闭)它,否则必须手动打开连接。在您的示例中,您正在使用适配器做什么?它似乎没有被使用? - Dan Def
1
@DanDef -- 是的,我为这个问题改编了一个使用数据适配器到数据读取器的片段;我的错。我不知道ExecuteReader不会打开连接,现在知道了。 - rory.ap
@rory.ap Using语句对性能有影响吗?我的意思是,如果我使用Using语句,它会使我的应用程序更快吗? - Jaa Zaib
@محمدخرمشھزاد -- 这不是关于让它更快,而是关于弹性和正确性。如果你的应用程序在读取数据时抛出异常,那么 using 语句确保所有可释放资源在块结束之前都将被释放。 - rory.ap

4
您的开启和关闭模式是正确的。然而,您必须注意,这并不会打开和关闭与 SQL Server 的连接,因此不会真正解决您对内存使用和 CPU 的担忧 - 实际上不会有任何区别。
开启和关闭的作用是向客户端PC的ADO连接池租赁和归还连接。这意味着关闭ADO连接并不能保证(在大多数情况下不会)关闭和释放与SQL Server的连接。这是因为建立和验证连接相对昂贵和缓慢,所以ADO连接池将保持您的连接处于池中仍然打开状态,以防您想重新建立连接。
对SQL Server产生影响的是需要执行的并发查询数量-以及查询返回的数据集大小以及数据库中数据总大小。
并发查询会挤占CPU,返回的数据集挤占可用RAM。显然,您的数据库越大,可以缓存在RAM中的内容就越少,因此在查询时更不可能获得缓存命中。
实践中我的经验是,除非您正在执行一些非常特定的操作,否则您在SQL Express版本和完整版本的SQL Server之间不会注意到任何区别;
1)编写允许用户构建用户定义或用户范围查询的BI样式工具。 2)编写糟糕的SQL - “大SQL”可以掩盖您的错误查询语法,但Express无法做到这一点,因为它可用的RAM更少。
如果您编写高效,受限制的SQL,则实际上可能永远不会达到SQL Express的任何限制。

感谢您详细回复。我有最多10个持续运行的查询。几个月来,我一直感到性能问题。我认为存在某些死锁。因为当我重新启动服务器时,一切都会恢复正常。那么,您认为这是“Express版本限制”引起的问题吗?我应该升级到“标准版”,还是应该重新检查我的C#代码是否存在漏洞? - Jaa Zaib
你有10个并发查询,或者说你正在循环运行10个查询?如果是10个在循环中运行的查询,那么SQL Express不是你的问题。即使你有10个无休止地运行的并发查询,我也不会指望SQL Express会有任何问题。重新启动服务器根本不会有任何影响。尝试所有正常的操作(例如Windows性能监视器、SQL Server Profiler)来查看服务器上发生了什么。 - PhillipH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接