我有一个简单的类,可以搜索PostgreSQL中的所有表并为它们生成SELECT
查询。工作正常,但需要关闭java.sql.Connection的建议我希望我的对象在示例仍然存在时保持数据库连接。要做到这一点,我创建了一个私有的Connection connection
字段,以便在调用每个方法后不会建立和关闭与数据库的连接(在一个会话期间),但是在主线程停止或bean被释放后创建一次并关闭。我尝试使用@PreDestroy
并实现DisposableBean
接口,但没有看到任何明确的结果。那么关闭这样的连接的正确方法是什么呢?
QueryBuilder类
@Component
public class PostgreSQLQueryBuilder implements SQLQueryBuilder{
private DatabaseMetaData metaData;
private Connection connection; // I need to close this somehow
@Autowired
public PostgreSQLQueryBuilder(DataSource dataSource) {
try {
this.connection = dataSource.getConnection();
this.metaData = connection.getMetaData();
} catch (SQLException e) {
System.out.println("Connection exception");
e.printStackTrace();
}
}
@Override
public String queryForTable(String tableName){
String resultQuery = null;
List<String> columnList = new ArrayList<>();
if (getTables().contains(tableName)) {
try (ResultSet columns = metaData.getColumns(null, null, tableName, null)) {
//some logic
return resultQuery;
} catch (SQLException e) {
System.out.println("Exception");
e.printStackTrace();
}
}
return resultQuery;
}
@Override
public List<String> getTables() {
List<String> tables = new ArrayList<>();
try (ResultSet schemaRs = metaData.getSchemas()) {
while (schemaRs.next()) {
String currentSchema = schemaRs.getString(1);
try (ResultSet tableRS = metaData.getTables(null, currentSchema, "%", new String[]{"TABLE", "SYSTEM TABLE"})) {
while (tableRS.next()) {
tables.add(tableRS.getString("TABLE_NAME"));
}
}
}
} catch (SQLException e) {
System.out.println("Exception");
e.printStackTrace();
}
return tables;
}
// I tried this
@PreDestroy
private void closeConnections(){
try{
this.connection.close()
//this is not printed
System.out.println("Connection closed")
}catch(Exception e){
//some logic
}
}
}
测试类别:
public class SQLQueryExtenderTest {
public static void main(String[] args) throws Exception{
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
applicationContext.start();
SQLQueryBuilder queryBuilder = applicationContext.getBean(SQLQueryBuilder.class);
List<String> tables = queryBuilder.getTables();
System.out.println(tables);
System.out.println(queryBuilder.queryForTable("some_table"));
System.out.println(queryBuilder.queryForTable("person"));
System.out.println(queryBuilder.queryForTable(null));
}
//I expect the connection to be closed at this point
}
2条答案
按热度按时间jv2fixgn1#
当不再需要JDBC连接等资源时,显式关闭它们是一个很好的做法。关闭资源有助于将它们释放回资源池,防止资源泄漏并节省系统资源。
在您的示例中,您可以在带有@PreDestroy注解的closeConnections()方法中关闭连接资源。该方法应在销毁bean时调用。
但是,您提到没有调用closeConnections()方法。这可能是由于在application context关闭时PostgreSQL QueryBuilder bean没有被销毁。要解决这个问题,您可以使用registerShutdownHook()方法向Spring ApplicationContext注册一个shutdown钩子。
下面是代码的更新版本,它在bean被销毁时关闭连接:
QueryBuilder类:
测试类别:
在此更新版本中,PostgreSQL QueryBuilder类实现了DisposableBean接口,并覆盖destroy()方法以调用closeConnections()方法。此外,SQLQueryExtenderTest类使用AnnotationConfigApplicationContext的registerShutdownHook()方法注册了一个关闭钩子,以确保在关闭应用程序上下文时调用closeConnections()方法。
nmpmafwu2#
在本例中,您可以使用@PreDestroy注解指定销毁bean时要调用的方法。在bean从容器中删除之前调用@PreDestroy方法。在此方法中,您可以关闭Connection对象和已打开的任何其他资源。
然而,在您的情况下似乎没有调用@PreDestroy方法。这可能是因为Spring容器没有正确管理您的bean。要解决这个问题,您可以通过使用@Component annotation来确保您的bean被定义为Spring bean。此外,您可以使用@Scope annotation来指定bean的范围。在您的情况下,可以使用@Scope(“prototype”)注解在每次从容器请求bean时创建一个新的bean示例。
下面的示例说明了如何修改代码以正确管理Connection对象:
通过这些更改,当您获得PostgreSQL QueryBuilder bean的新示例时,Spring将注入DataSource对象,创建新的Connection对象,并将其存储在connection字段中。当bean被销毁时,@PreDestroy方法将被调用,Connection对象将被关闭。