假设我有一个打开数据库连接的 Java 应用程序。通常我会在 finally 块中添加一个 connection.close() ,但是在 kill 操作或任何其他异常终止的情况下不会执行此块,不是吗?作为程序员,我是否可以采取任何其他预防措施以便在应用程序退出之前正确关闭连接?
6 回答
您应该查看 Java 的 Runtime.addShutdownHook() 方法(http://java.sun.com/javase/6/docs/api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread))。它允许您添加一个将在虚拟机终止时调用的钩子。您可以使用它来调用清理例程。
那将是一个 TERM 信号。KILL 信号将杀死进程并且不允许它进行任何清理(因为接收进程无法捕获或忽略 KILL 信号)。
如果某些外部因素杀死了您的程序,那么您将无能为力。显然他们想阻止它,那你怎么能阻止他们呢?
我打算建议一个关闭挂钩,但 Javadocs 状态:
在极少数情况下,虚拟机可能会中止,即停止运行而没有完全关闭。当虚拟机在外部终止时会发生这种情况,例如
SIGKILL
在 Unix 或TerminateProcess call
Microsoft Windows 上使用信号终止。如果本地方法出错,例如破坏内部数据结构或尝试访问不存在的内存,虚拟机也可能中止。如果虚拟机中止,则无法保证是否会运行任何关闭挂钩。
(强调我的)
终止程序最终会使TCP
从程序到[Oracle|SQL Server|MySQL|PostgreSQL]
服务器的流超时。
服务器将看到它并回滚任何待处理的事务。
- 您不需要在应用程序关闭时调用 connection.close(),因为所有打开的文件都会被操作系统自动关闭。
- 此外,连接的 finalize() 方法应该在应用程序自动关闭之前运行(如果关闭是正常的,而不是 ABORTed),并且应该关闭连接。
- 在任何情况下,您都可以注册shutdown-hooks来执行您需要的任何清理工作(同样,将在正常关闭情况下运行,而不是 ABORT)。
当您真的被杀死时(kill -9
在 UNIX 上),您无法对此采取任何措施。
A finally
-block 是您能做的最多的事情,请参阅SO:在 Java 中,是否保证调用“finally”块(在 main 方法中)?详情。
某种程度的异常终止是不可避免的。您如何捕捉到电源线被拉到服务器上的事件?