Java SQL .close() 是否需要继续重新实例化对象?
Java SQL .close() necesary if keep re-instantiating object?
我知道,如果您创建 SQL PreparedStatement 或 ResultSet,您应该在完成后对资源使用 .close()。但是,如果我正在循环并在每次迭代时重新创建 PreparedStatement,我是否仍然需要在每次迭代期间或在我完成时调用 .close()?
例如,如果我有这个:
private Connection con;
private String[] queries;
private PreparedStatement stmt;
...
create connection
fill array queries with 10 queries in it
...
for (int i = 0; i < 10; i++) {
stmt = con.prepareStatement(queries[i], Statement.RETURN_GENERATED_KEYS);
stmt.executeUpdate();
// necessary?
stmt.close()
}
每次迭代都需要 .close() stmt,还是应该在循环完成时才执行?为什么或者为什么不?谢谢。
每次迭代都会创建一个新对象。您保持打开状态的每个语句都可以使资源在数据库服务器上打开的时间超过必要的时间。关闭连接应该会清理所有内容,但是 JDBC 驱动程序已知存在无法清理的错误。
在 finally 块中将它们全部关闭,或者对资源使用 try。
对象在超出范围后继续存在
当您将引用变量重新分配给另一个对象时,之前引用的对象仍然存在于内存中。他们的close
方法未被调用。
如果没有在其他地方引用,孤立对象将成为垃圾收集的候选者。但是垃圾回收不会调用对象的close
方法。
尝试使用资源
您应该学习使用 try-with-resources 语法来自动关闭资源,例如 JDBC 对象、文件 I/O 对象等。请参阅 Oracle 的 tutorial。尽快关闭此类资源,尽快关闭它们。
示例代码
您的代码应类似于以下示例代码。请注意每个 JDBC 对象在我们使用完后如何立即关闭:Connection
、PreparedStatement
和 ResultSet
.
A DataSource
对象不会关闭,因为它实际上并未“打开”。 DataSource
对象仅包含连接到数据库所需的信息(服务器地址、用户名、密码等)。
String[] queries = new String[ 10 ];
// … populate queries array.
DataSource dataSource = this.fetchDataSource();
try (
Connection conn = dataSource.getConnection() ;
)
{
for ( int i = 0 ; i < 10 ; i++ )
{
try (
PreparedStatement ps = conn.prepareStatement( queries[ i ] , Statement.RETURN_GENERATED_KEYS ) ;
)
{
ps.setObject( 1 , LocalDate.of( 2021 , Month.JANUARY , 23 ) );
int countOfRowsAffected = ps.executeUpdate();
if ( countOfRowsAffected > 0 )
{
try ( ResultSet rs = ps.getGeneratedKeys() ; )
{
while ( rs.next() )
{
// … process your keys.
}
}
// The `ResultSet` object is auto-closed by this point.
}
}
// The `PreparedStatement` object is auto-closed by this point.
}
} catch ( SQLFeatureNotSupportedException e )
{
e.printStackTrace();
} catch ( SQLTimeoutException e )
{
e.printStackTrace();
} catch ( SQLException e )
{
e.printStackTrace();
}
// The `Connection` object is auto-closed by this point.
使用 try-with-resources 的一个额外好处是您的意图非常明确。阅读您的代码的任何人都知道您打算在何处关闭每个资源。
我知道,如果您创建 SQL PreparedStatement 或 ResultSet,您应该在完成后对资源使用 .close()。但是,如果我正在循环并在每次迭代时重新创建 PreparedStatement,我是否仍然需要在每次迭代期间或在我完成时调用 .close()?
例如,如果我有这个:
private Connection con;
private String[] queries;
private PreparedStatement stmt;
...
create connection
fill array queries with 10 queries in it
...
for (int i = 0; i < 10; i++) {
stmt = con.prepareStatement(queries[i], Statement.RETURN_GENERATED_KEYS);
stmt.executeUpdate();
// necessary?
stmt.close()
}
每次迭代都需要 .close() stmt,还是应该在循环完成时才执行?为什么或者为什么不?谢谢。
每次迭代都会创建一个新对象。您保持打开状态的每个语句都可以使资源在数据库服务器上打开的时间超过必要的时间。关闭连接应该会清理所有内容,但是 JDBC 驱动程序已知存在无法清理的错误。
在 finally 块中将它们全部关闭,或者对资源使用 try。
对象在超出范围后继续存在
当您将引用变量重新分配给另一个对象时,之前引用的对象仍然存在于内存中。他们的close
方法未被调用。
如果没有在其他地方引用,孤立对象将成为垃圾收集的候选者。但是垃圾回收不会调用对象的close
方法。
尝试使用资源
您应该学习使用 try-with-resources 语法来自动关闭资源,例如 JDBC 对象、文件 I/O 对象等。请参阅 Oracle 的 tutorial。尽快关闭此类资源,尽快关闭它们。
示例代码
您的代码应类似于以下示例代码。请注意每个 JDBC 对象在我们使用完后如何立即关闭:Connection
、PreparedStatement
和 ResultSet
.
A DataSource
对象不会关闭,因为它实际上并未“打开”。 DataSource
对象仅包含连接到数据库所需的信息(服务器地址、用户名、密码等)。
String[] queries = new String[ 10 ];
// … populate queries array.
DataSource dataSource = this.fetchDataSource();
try (
Connection conn = dataSource.getConnection() ;
)
{
for ( int i = 0 ; i < 10 ; i++ )
{
try (
PreparedStatement ps = conn.prepareStatement( queries[ i ] , Statement.RETURN_GENERATED_KEYS ) ;
)
{
ps.setObject( 1 , LocalDate.of( 2021 , Month.JANUARY , 23 ) );
int countOfRowsAffected = ps.executeUpdate();
if ( countOfRowsAffected > 0 )
{
try ( ResultSet rs = ps.getGeneratedKeys() ; )
{
while ( rs.next() )
{
// … process your keys.
}
}
// The `ResultSet` object is auto-closed by this point.
}
}
// The `PreparedStatement` object is auto-closed by this point.
}
} catch ( SQLFeatureNotSupportedException e )
{
e.printStackTrace();
} catch ( SQLTimeoutException e )
{
e.printStackTrace();
} catch ( SQLException e )
{
e.printStackTrace();
}
// The `Connection` object is auto-closed by this point.
使用 try-with-resources 的一个额外好处是您的意图非常明确。阅读您的代码的任何人都知道您打算在何处关闭每个资源。