在 Java 和 C# 中,它们都有类似 System.terminate() 的东西。如果我的程序有打开的数据库连接、数据库读取器和数据库命令变量,并且我在 catch 子句中终止了我的程序,数据库资源是否仍然在使用中?还是因为我的整个程序刚刚退出,它们会自动释放?
通常,我应该如何处理这种情况以确保我始终释放数据库连接,无论是通过正常程序终止还是意外程序终止?有什么好的做法吗?
在 Java 和 C# 中,它们都有类似 System.terminate() 的东西。如果我的程序有打开的数据库连接、数据库读取器和数据库命令变量,并且我在 catch 子句中终止了我的程序,数据库资源是否仍然在使用中?还是因为我的整个程序刚刚退出,它们会自动释放?
通常,我应该如何处理这种情况以确保我始终释放数据库连接,无论是通过正常程序终止还是意外程序终止?有什么好的做法吗?
进程终止后,所有相关资源(包括内存、句柄、连接等)都将被释放。
通常,在 C# 中,您将使用 Dispose 模式/using
语句来控制稀缺资源。
除非您专门关闭连接,否则它们将保持打开状态,直到超时。
我曾几次在 C# 中发现了这一点。最佳实践要求关闭/关闭您知道不再需要的资源。文件 I/O 流、数据库连接等
在 C# 中,如果在被垃圾收集的对象中实现了终结器,则垃圾收集器会完成隐式清理。任何非托管资源的清理,例如数据库连接,都可以在 Dispose 方法中完成。
有关更多信息,请参阅这篇文章:
实施 Finalize 和 Dispose 以清理非托管资源
http://msdn.microsoft.com/en-us/library/b1yfkh5e(VS.71).aspx
当一个进程终止时,它打开的所有文件描述符都应该被操作系统释放。文件描述符包括文件和套接字,它们通常会涵盖您的数据库连接。
所有这一切都告诉您,当您的客户端终止时,它的连接将关闭。它不会告诉你服务器做了什么。根据其编写方式,服务器完全有可能继续保持其连接打开,期待来自客户端的消息永远不会到达,甚至尝试发送数据。这些最终可能会超时,但这可能没有经过精心计划。(对于一个像样的 RDBMS 来说应该是这样,但可能不是。)因此,根据您的 RDBMS,您可能需要采取一些步骤来告诉服务器您正在关闭,以便告诉它释放其资源。
如果您正在使用 SQL Server,您可以查看 sysprocesses 或运行 sp_who2。我在我的机器上测试了这个并且连接确实关闭了,即:
Console.Write("Opening connection");
Console.ReadLine();
SqlConnection connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=SeniorMail;Integrated Security=SSPI;");
connection.Open();
SqlCommand command = new SqlCommand("SELECT count(*) from Account", connection);
Console.Write("Running sql");
Console.ReadLine();
int? count = command.ExecuteScalar() as int?;
Console.Write("Now I'll throw an exception");
Console.ReadLine();
int a = 0, b = 1, c = 0;
try
{
c = b / a;
}
catch
{
Environment.Exit(1);
}
我检查了“现在我将抛出异常”的任何一侧的 sp_who2,我可以看到应用程序退出后连接已经消失。
一般的 POSIX 行为是,当程序终止时,所有文件句柄、网络连接等都将关闭。另一端在这一点上是否做正确的事情是一个悬而未决的问题,但如果您使用任何相当流行的 RDBMS,它会很好。
在 C# 中,您通常会在使用它们后立即关闭连接,例如:
using(SqlConnection connection = ...)
{
... do something ...
} // connection disposed / closed here
但是,通常您将使用连接池,而这一切只是将连接返回到池中。因此,您的进程仍将与数据库服务器建立活动连接。
如果你干净地关闭,连接池无疑会被清理,与数据库的实际连接将被关闭(你可以通过查看数据库服务器上打开的连接来验证这一点)。
但是在某些情况下(例如调用 Environment.FailFast),应用程序可能会在没有关闭连接的情况下崩溃——在这种情况下,它们最终会超时并被数据库服务器关闭。
它应该在下一次 GC 时被清除,但准确地说,在 C# 中,您可以在结构化异常处理的 finally 块上关闭连接。
try {
// open DB connection
} catch (Exception ex) {
// deal with exception
} finally {
// close and dispose connection
}