在我的网络应用程序中,我广泛使用数据库。
我有一个抽象的servlet,继承了所有需要数据库连接的servlet。该抽象servlet创建数据库连接,调用抽象方法,该方法必须由继承的servlet覆盖以执行其逻辑,然后关闭连接。我不使用连接池,因为我的应用程序将拥有非常有限的用户和操作。
我的问题是,如果我没有关闭我继承的servlet创建的ResultSet
,PreparedStatement
和Statement
,那么最糟糕的情况是什么?创建它们的{1}}总是关闭的吗?
答案 0 :(得分:9)
Statement#close()的javadoc说:
注意:当Statement对象关闭时,它的当前ResultSet对象(如果存在)也将关闭。
因此,只要您始终及时关闭语句,您就不必担心关闭ResultSet。
Connection#close()的javadoc没有做出相应的保证,但确实说:
立即释放此Connection对象的数据库和JDBC资源,而不是等待它们自动释放。
您可以合理地解释为暗示任何陈述将被关闭。看一下开源的jTDS驱动程序,并窥探一个众所周知且昂贵的商业数据库的驱动程序,我可以看到它们就是这样做的。
答案 1 :(得分:5)
我非常确定关闭连接会关闭相关的语句,结果集和其他相关对象。但是,所有这些都将消耗客户端上的资源,并且可能在数据库服务器上,直到连接关闭。
如果在您的情况下您知道您将很快关闭连接 ,您可能不会冒很大的风险,尽管我认为这不应被视为最佳做法。
但是这仅在您当前的设置中有效。 如果当您的应用程序发生变化时,您可能会遇到问题,因为您没有关闭您的语句和结果集。
虽然您不想使用连接池,但我认为即使用户/操作很少也是一个坏主意,因为打开数据库连接并不便宜。因此,即使在您的上下文中,连接池也可能有助于提高系统响应速度。
关于垃圾收集的说明。在关闭连接之前,未使用的语句或结果集可以进行GCed。 但当涉及释放系统资源(如文件或更一般的非Java资源(例如数据库服务器上的游标))时,不应依赖JVM GC。例如,如果您的客户端应用程序打开了很多ResultSet但只使用了分配的堆内存的一小部分,那么当打开的游标将数据库服务器窒息时,GC将永远不会启动。
答案 2 :(得分:1)
AFAIK,由于绑定文件句柄,保存与给定语句关联的结果集所需的资源等,您最终会耗尽数据库服务器上的资源。可能存在智能驱动程序/数据库实现,确保一旦连接关闭,所有相关的资源都会被释放,但这不是规范的一部分,所以最终可能会让你感到厌烦。您的重写类无法关闭它们使用的结果集和语句的原因是什么?
答案 3 :(得分:1)
它的一些废话Api - 最终你写了一堆锅炉板代码。
我认为最好的方法是将类包装起来,然后设置它以便处理连接来处理其他内容(因为你可以跟踪在包装调用的路上发生了什么)。
只要你有一个IDE可以生成你在课堂上委派方法,那么包装这样的东西是一项微不足道的工作。
我没有意识到所有需要处理的额外内容,但只是发现有人在这里进行处理,但是我很幸运,因为我们已经包装了基本类,将所有烦人的异常转换为RuntimeExceptions并且提供一些更高级别的SQL操作。
我做了一个小班来跟踪不同的东西:
public class CleanupList
{
private final ArrayList<AutoCloseable> _disposables;
public CleanupList()
{
_disposables = new ArrayList<>();
}
public void cleanup()
{
for(AutoCloseable closeable : _disposables){
//it sucks that they put an exception on this interface
//if anyone actually throws an exception in a close method then there's something seriously wrong going on
//they should have copied the c# more closely imo as it has nicer syntax aswell
try
{
closeable.close();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
_disposables.clear();
}
public <T extends AutoCloseable> T track(T statement)
{
_disposables.add(statement);
return statement;
}
}
然后例如在Wrapped Connection中(这是包装数据库连接的东西):
public class WrappedConnection implements AutoCloseable
{
private final CleanupList _cleanupList;
private Connection _connection;
public WrappedConnection(Connection connection)
{
_connection = connection;
_cleanupList = new CleanupList();
}
public void close()
{
try
{
_connection.close();
_cleanupList.cleanup();
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
}
public PreparedStatement prepareStatement(String sql)
{
try
{
return trackForDisposal(_connection.prepareStatement(sql));
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
}
private <T extends AutoCloseable> T trackForDisposal(T statement)
{
return _cleanupList.track(statement);
}
.... lots more methods
}
然后,您也可以将相同的列表传递给PreparedStatement / Result集的包装版本(我在此处未显示)等,并以类似的方式使用它。
我不知道其他人在使用什么,但在IDEA中,您可以为使用(或者我应该说是资源试用)块中的自动关闭内容启用警告:
try(SomethingThatNeedsClosing somethingThatNeedsClosing = new SomethingThatNeedsClosing()){
//do stuff
}
这些使用块最后会自动关闭并且只能用于AutoClosable接口类型的东西
我不知道为什么在IDEA默认情况下这个警告没有打开,但是你去了。
答案 4 :(得分:0)
与数据库的连接并不是您的应用程序唯一的用途。还有其他资源受到威胁。
如果你不自己释放它们,它们会在某个时间点被释放,但如果能够这样做,你应该这样做。