为什么MySQL PreparedStatements在GC上不会自动在Java中关闭?

时间:2016-05-13 16:38:34

标签: java mysql garbage-collection

在我早期的Java Web应用程序中,我会在每个请求结束时close Connection。我不会关闭ResultSetPreapredStatement,因为它们会在Connection关闭时自动关闭。

但是,我的一些应用程序必须在循环中创建许多PreparedStatement。因此,如果我没有单独close他们,我会在请求完成之前收到OutOfMemory错误。似乎每个Connection都会保留对其所有PreparedStatement的引用。

当变量变得不可访问时(即子例程返回),我习惯于Perl自动清理语句($sth)。如果我在致电$sth时仍然可以访问$dbh->disconnect,那么我必须致电$sth->finish,但大多数时候我的脚本无法访问,而且这不是必需的。

我认为Java可以使用finalize方法并可能使用WeakReference为开发人员提供类似的便利。当所有引用都消失且对象不可访问时,将调用finalize方法。 (使用弱引用除外)

  1. 这是自动关闭PreparedStatement的合理解决方案吗?如果是这样,我计划创建包装函数以在我的应用程序中实现这种自动化。如果这不是一个合理的解决方案,请解释。

  2. 阻止MySQL-Java Connector(JDBC驱动程序)的设计人员在原始设计中包含此自动化的可能副作用是什么?

  3. 我能想到的唯一副作用是MySQL服务器本身的内存开销。但是,当PreparedStatement仍然打开时,我不知道MySQL服务器是否有任何开销。 MySQL中是否存在任何内存开销?

2 个答案:

答案 0 :(得分:0)

当JVM决定它需要时,finalize方法运行 - 当对象超出范围时,它可能会也可能不会运行。例如,它与C ++析构函数不同。您不需要在循环中创建PreparedStatements - 整点是它们已经“准备好”并且可以多次使用。这并不意味着它应该永远存在,但如果在你的例子中你需要循环某些东西,它应该被重用。

简而言之 - 永远不要指望敲定。如果你打开一些东西然后关闭它。如果可能的话,在新代码中使用AutoClosable接口,这样您就不必担心了。

答案 1 :(得分:0)

  

我以前用Perl自动清理语句

我可以想象两个原因:

  • Connection可能与Driver强烈引用。这可以由WeakReference取代,但它不会做你需要的(见下文)。
  • Perl有许多内置的特殊功能,使编程更方便,这可能是其中之一:"当一个变量可以在离开子时被释放时,它将被释放。"
  

我认为Java可以使用finalize方法为开发人员提供类似的便利,并可能使用WeakReference

没办法。 GC只是回收内存的工具,滥用其他任何不起作用的工具(见下文)。

  
      
  1. 这是自动关闭PreparedStatement的合理解决方案吗?
  2.   

没有。它的所有优点都在于帮助您了解是否以及在何处泄漏资源,以便您可以解决问题。问题是其他资源可能会更快耗尽,留下大量内存,但是没有单一的免费文件描述符。因此,GC不会触发。您可以手动拨打System.gc,但这会浪费很多时间。

  
      
  1. 阻止MySQL-Java Connector的设计者将这种自动化纳入其原始设计的可能副作用是什么?
  2.   

它无法运作。如果有可能,那么它将在JDBC中实现,以便驱动程序作者不需要打扰。

  
      
  1. 我能想到的唯一副作用是MySQL服务器本身的内存开销。
  2.   

我打赌,当MySQLConnection关闭时,它会告诉服务器释放相关资源。有such resources

我强烈建议您忘记使用GC。 Java中没有完美的解决方案,但有许多好的解决方案:

  • 从Java 7开始,您可以使用try-with-resources
  • 您可以使用Project Lombok中的@Cleanup
  • 如果您有足够的内存,您可以编写一个完成所有工作的课程,包括清理并将ResultSet转换为List<Object[]>
  • 您可以使用Template method pattern指定如何处理结果行的抽象方法。
  • 您可以使用其中的千种工具....