简体   繁体   English

C# - 关闭Sql对象的最佳实践

[英]C# - closing Sql objects best practice

If you have a C# function with Sqlaccess, is it mandatory to close all objects/handles, or is everything cleaned up automatically once you exit the function 如果你有一个带有Sqlaccess的C#函数,是否必须关闭所有对象/句柄,或者在退出函数后自动清理所有内容

For example: 例如:

void DoSqlStuff()
{
    SqlConnection sqlConn = new SqlConnection(...);
    SqlCommand cmd = new SqlCommand(...);
    SqlDataReader sqlData= null;

    sqlConn,Open();
    sqlData = cmd.ExecutReader();


    while(sqlData.Read())
    {
         ...
    }
}

Is it optional, recommended or mandatory to close SqlConn and SqlData? 关闭SqlConn和SqlData是可选的,推荐的还是必需的?

Thanks. 谢谢。

You should close the SqlConnection object as soon as you're done with it. 您应该在完成后立即关闭SqlConnection对象。 If you don't then the connection will remain open, and will not be available to handle other requests. 如果不这样做,则连接将保持打开状态,并且无法处理其他请求。

The using statement is useful for this. using语句对此很有用。 It will call Dispose() on the object for you: 它将为您调用对象上的Dispose():

using (SqlConnection cn = new SqlConnection(connectionString))
{   
    SqlCommand cm = new SqlCommand(commandString, cn)
    cn.Open();
    cm.ExecuteNonQuery();       
}

You don't need to have a separate using statement for the SqlDataReader (as well as one using statement for the connection) unless you plan do perform other operations with the connection after the SqlDataReader has fully read through the row set. 您不需要为SqlDataReader(以及一个using语句用于连接)使用单独的using语句,除非您计划在SqlDataReader完全读取行集之后对连接执行其他操作。

If you are just opening a connection, reading some data using the reader, and then closing the connection, then one using statement for the entire block of code (surrounding the connection) will suffice as the garbage collector will clean up all resources tied to the connection that is disposed by the first using statement. 如果您只是打开一个连接,使用阅读器读取一些数据,然后关闭连接,那么一个使用语句的整个代码块(围绕连接)就足够了,因为垃圾收集器将清理所有与之关联的资源。由第一个using语句处理的连接。

Anyway, here's a good article that describes it all... 无论如何,这是一篇描述这一切的好文章 ......

You should close everything before returning from the function. 您应该在从函数返回之前关闭所有内容。 Open datareaders mean open cursors on the database, resulting in increased memory usage. Open datareaders意味着数据库上的开放游标,导致内存使用量增加。 Same goes for database connections. 数据库连接也是如此。

Unused objects are not immediately freed in C#, but only when garbage collection is performed, which is not deterministic. 未使用的对象不会立即在C#中释放,而是仅在执行垃圾收集时释放,这不是确定性的。

Be careful with absolutes here. 在这里要小心绝对。 A lot depends on what you are doing & where the inefficiencies may lie. 很大程度上取决于你在做什么以及效率低下的地方。 In a Web Page where each user has a separate security context you may have no choice but to establish a new SQL connection with new security credentials with each page hit. 在每个用户都有一个单独的安全上下文的Web页面中,您可能别无选择,只能使用每个页面命中的新安全凭据建立新的SQL连接。 Clearly nicer if you can use a pool of SQL connections with a shared security context & let the Web page filter the results but perhaps you can't. 如果您可以使用具有共享安全上下文的SQL连接池并让网页过滤结果,那么显然更好,但也许您不能。

In early versions of SQL Server ie (v6.5 or less) the Login Authentication was done by SQL Server. 在早期版本的SQL Server即(v6.5或更低版本)中,登录验证由SQL Server完成。 Also SQL was severely constrained by connection memory & the number of active connections it could handle. 此外,SQL受到连接内存和它可以处理的活动连接数的严重限制。 So it was a great idea to drop your connection when not in use. 因此,在不使用时断开连接是一个好主意。 Post v6.5, most people use Windows Authentication to login to SQL. 在v6.5之后,大多数人使用Windows身份验证登录SQL。 This causes a lot of network calls between servers & some latency. 这会导致服务器之间的大量网络呼叫和一些延迟。 Kerberos Security is even more chatty, Thus establishing a SQL connection is expensive. Kerberos安全性更加繁琐,因此建立SQL连接非常昂贵。 For that reason you need to find a balance between Holding a connection open for the life of your WinForms application vs Opening & closing it within each method call. 因此,您需要在WinForms应用程序的生命周期中保持连接打开与在每个方法调用中打开和关闭它之间找到平衡。

As a rough guide, if you think your app is going to want to talk to SQL in the next, say 30 secs. 作为一个粗略的指南,如果你认为你的应用程序想要在下一个与SQL交谈,比如30秒。 Keep the established connection open. 保持已建立的连接打开。 If they've minimised your app, not touched it within a timeout period, or you've got all the data in RAM & they are unlikely to need anything more from the SQL system. 如果他们已经最小化了你的应用程序,没有在超时期限内触及它,或者你已经获得了RAM中的所有数据,他们不太可能需要SQL系统中的任何其他内容。 Close the connection. 关闭连接。

Consider creating a Class with a System Timer to hold the connection. 考虑创建一个带有系统计时器的类来保持连接。 Your class will always provide a valid connection, but perhaps the class will choose to drop it & free the connection load on SQL when appropriate. 您的类将始终提供有效的连接,但是类可能会选择删除它并在适当时释放SQL上的连接负载。

Unless you are also writing Server based code, a small amount of memory inefficiency might not even be noticed. 除非您也在编写基于服务器的代码,否则可能甚至不会注意到少量的内存效率低下。 But 2-10,000 clients all poorly using your Security & Data Servers is likely to bring your Data Centre to its knees. 但是,有2-10,000名客户使用您的安全和数据服务器,可能会使您的数据中心陷入困境。

All three classes have a Dispose() method. 这三个类都有Dispose()方法。 Mandatory is too strong, but definitely highly recommended you use the using keyword so Dispose() is automatically called. 强制性太强,但强烈建议您使用using关键字,以便自动调用Dispose()。 Failing to do so makes your program run "heavy", using more system resources than necessary. 如果不这样做会使您的程序运行“繁重”,使用的系统资源比必要的多。 And outright failure when you don't use the "new" keyword enough to trigger the garbage collector. 当你不使用足够触发垃圾收集器的“new”关键字时,会彻底失败。

Calling Close on the SQL connection won't actually close it, but will return it to a connection pool to be reused, improving performance. 在SQL连接上调用Close实际上不会关闭它,但会将其返回到连接池以便重用,从而提高性能。

Additionally it is generally poor practice to not explicitly dispose of unmanaged resources when you are finished with them (asap). 另外,当你完成它们时(asap)没有明确处理非托管资源通常是不好的做法。

Explicit disposing in the finally statement is another approach, although the using statement is a much better solution. finally语句中的显式处理是另一种方法,尽管using语句是一个更好的解决方案。 It produces a bit more code, but demonstrates the goal... 它产生了更多的代码,但展示了目标......

SqlConnection conn = null;
try
{
    //create connection

    SqlCommand cmd = null;
    try
    {
        //create command

        SqlDataReader reader = null;
        try 
        {
            //create reader
        }
        finally
        {
            reader.Dispose();
        }
    }
    finally
    {
        cmd.Dispose();
    }
}
finally 
{
    conn.Dispose();
}

Any class handling SQL stuff like Connections should implement the IDisposable interface as stated by Microsoft .NET coding guidelines. 任何处理像Connections这样的SQL东西的类都应该实现Microsoft .NET编码指南所述的IDisposable接口。

Thus, you should probably close and dispose your connection in your Dispose method. 因此,您应该关闭并在Dispose方法中处置连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM