JDBC SQLConnection关闭机制疑问:异步查询未结束为何无法关闭连接?
JDBC连接无法在异步SQL查询前关闭,必须等待查询完成
我原本期望在异步执行SQL查询前同步关闭JDBC连接,但实际发现SQL连接必须等查询执行完成后才会关闭。我尝试通过Thread.sleep增加查询执行时间,结果查询成功执行后,sqlConnection.close()才会执行。
相关代码
public static Future<List<JsonObject>> queryExecuter(JDBCClient jdbcClient, int id,String type) { Promise<List<JsonObject>> promise = Promise.promise(); jdbcClient.getConnection(sqlConnection->{ if(sqlConnection.succeeded()) { DTOQueryInfo dtoQueryInfo = queryHelper(sqlConnection.result(), id, type); //Execute query sqlConnection.result().queryWithParams(dtoQueryInfo.getSqlString(), dtoQueryInfo.getParams(), fetchSequenceResult->{ if (fetchSequenceResult.succeeded()) { if (fetchSequenceResult.result()==null || fetchSequenceResult.result().getRows()==null || fetchSequenceResult.result().getRows().isEmpty()) { logger.info("Query with no result "); promise.fail("Failed!"); }else { logger.info("Query Result:{} ", fetchSequenceResult.result().getRows()); promise.complete(fetchSequenceResult.result().getRows()); } } else { logger.error("Unable to inquiryActions :{}", fetchSequenceResult.cause()); promise.fail(new WSEXCP_NoAccessDefinedToNode(Integer.parseInt(String.valueOf(101)+String.valueOf(941)), "خطای داخلی. لطفا با راهبر سامانه تماس بگیرید.", HttpStatusEnum.SERVER_ERROR.getMin())); } }); } else { logger.error("خطای اتصال به دیتابیس : ", sqlConnection.cause()); promise.fail("خطای اتصال به دیتابیس"); } sqlConnection.result().close(); }); return promise.future(); }
问题分析
你的逻辑存在两个核心问题:
- 概念误区:SQL查询必须依赖活跃的数据库连接才能执行,在查询前关闭连接是完全不符合JDBC规范的操作,不可能实现。你实际需要的应该是查询完成后自动关闭连接。
- 代码逻辑错误:
queryWithParams是Vert.x提供的异步非阻塞方法,它会立刻发起查询并返回,不会等待结果。你把close()放在getConnection回调的外层,理论上会在发起查询后立刻关闭连接,但Vert.x的JDBC客户端内部做了同步保护,确保查询操作完成前不会真正关闭连接,这才导致你看到查询完成后close()才执行的现象。
修正后的代码
将连接关闭操作移到查询回调的try-finally块中,确保无论查询成功或失败,都在处理完结果后关闭连接:
public static Future<List<JsonObject>> queryExecuter(JDBCClient jdbcClient, int id,String type) { Promise<List<JsonObject>> promise = Promise.promise(); jdbcClient.getConnection(sqlConnection->{ if(sqlConnection.succeeded()) { SQLConnection conn = sqlConnection.result(); DTOQueryInfo dtoQueryInfo = queryHelper(conn, id, type); conn.queryWithParams(dtoQueryInfo.getSqlString(), dtoQueryInfo.getParams(), fetchSequenceResult->{ try { if (fetchSequenceResult.succeeded()) { if (fetchSequenceResult.result() == null || fetchSequenceResult.result().getRows() == null || fetchSequenceResult.result().getRows().isEmpty()) { logger.info("Query with no result "); promise.fail("Failed!"); } else { logger.info("Query Result:{} ", fetchSequenceResult.result().getRows()); promise.complete(fetchSequenceResult.result().getRows()); } } else { logger.error("Unable to inquiryActions :{}", fetchSequenceResult.cause()); promise.fail(new WSEXCP_NoAccessDefinedToNode( Integer.parseInt(String.valueOf(101)+String.valueOf(941)), "خطای داخلی. لطفا با راهبر سامانه تماس بگیرید.", HttpStatusEnum.SERVER_ERROR.getMin() )); } } finally { // 无论查询结果如何,最后关闭连接 conn.close(closeResult -> { if (closeResult.failed()) { logger.error("关闭数据库连接失败: ", closeResult.cause()); } }); } }); } else { logger.error("خطای اتصال به دیتابیس : ", sqlConnection.cause()); promise.fail("خطای اتصال به دیتابیس"); } }); return promise.future(); }
修正说明
- 提前将连接对象赋值给
conn变量,避免重复调用sqlConnection.result(),提升代码可读性和性能 - 使用
try-finally块保证连接关闭操作一定会执行,避免连接泄漏 - 调用
conn.close()时传入回调,可以捕获并处理关闭连接时的异常 - 连接会在查询操作完全完成(成功或失败)后才被关闭,符合异步JDBC操作的正确逻辑
内容的提问来源于stack exchange,提问作者Amir
相关产品推荐
相关产品推荐

