使用单个JDBC Statement对象执行多个查询

请在将此标记为重复之前阅读。 我从谷歌和SO搜索了很多,但我无法找到我想要的确切答案。

我的问题:在JDBC中,我可以使用单个Statement对象多次调用executeQuery("")吗? 安全吗? 或者我应该在每次查询后关闭语句对象,并创建新对象以执行另一个查询。

例如:

 Connection con; Statement s; ResultSet rs; ResultSet rs2; try { con = getConnection(); s = con.prepareStatement(); try { rs = s.executeQuery("......................."); // process the result set rs } finally { close(rs); } // I know what to do to rs here // But I am asking, should I close the Statement s here? Or can I use it again for the next query? try { rs2 = s.executeQuery("......................."); // process the result set rs2 } finally { close(rs2); } } finally { close(s); close(con); } 

是的,您可以重复使用Statement (特别是PreparedStatement ),并且通常应该使用JDBC。 如果你没有重复使用你的语句并立即创建另一个相同的Statement对象,那将是低效和糟糕的风格。 关闭它,将它关闭在finally块中是合适的,就像你在这个片段中一样。

有关您要求的示例,请查看此链接: jOOq文档

我不知道你为什么这么问。 API设计和文档显示,为多个executeexecuteUpdateexecuteQuery调用重用Statement对象是完全正确的(甚至是打算)。 如果不允许在Java文档中明确记录(并且可能API会有所不同)。

此外, Statement的apidoc说:

Statement接口中的所有执行方法都隐式关闭一个statment的[ sic ]当前ResultSet对象(如果存在open对象)。

这表明您可以多次使用它。

TL; DR:是的,您可以多次调用单个Statement对象上的execute ,只要您意识到之前打开的任何ResultSet都将被关闭。

您的示例错误地使用了PreparedStatement ,并且您不能(或者:不应该)调用任何接受 PreparedStatement上的Stringexecute...方法 :

SQLException – 如果在PreparedStatementCallableStatement该方法

但也要回答PreparedStatementPreparedStatement的全部目的是预编译带参数占位符的语句,并将其重用于具有不同参数值的多次执行。

我在API文档中找不到任何会说明你不应该在给定的PreparedStatement实例上多次调用executeQuery()内容。

但是,您的代码不会关闭PreparedStatement – 对executeQuery()的调用会在这种情况下抛出SQLException – 但是executeQuery()返回的ResultSet 。 重新执行PreparedStatement时,ResultSet会自动关闭 。 根据您的具体情况,您应该关闭它,当您不再需要它时。 我会关闭它,因为我认为不这样做是不好的。

更新 Upps,我错过了两个试块之间的评论。 如果此时关闭PreparedStatement,则无法在不获取SQLException的情况下再次调用executeQuery()。

Prepared Statement告诉数据库记住您的查询并准备接受在该查询中执行的参数化变量。 这很像存储过程。

Prepared Statement完成两件主要的事情:

  1. 它会自动转义查询变量以防止SQL注入。

  2. 它告诉数据库记住查询并准备好接受变量。

数字2很重要,因为这意味着数据库只需要解释一次您的查询,然后就可以使用该程序了。 所以它提高了性能。

您不应该在执行调用之间关闭预准备语句和/或数据库连接。 这样做是非常低效的,并且它会比使用普通的旧Statement带来更多的开销,因为每次指示数据库创建一个过程并记住它。 即使数据库配置为“热点”并且即使您关闭PreparedStatement仍然会记住您的查询,您仍然会产生网络开销以及较小的处理时间。

简而言之,保持ConnectionPreparedStatement打开,直到完成它们为止。

编辑:要注释不从执行中返回ResultSet ,这很好。 executeQuery将为刚刚执行的任何查询返回ResultSet

首先,我对你的代码感到困惑

 s = con.prepareStatement(); 

它运作良好吗?我在JAVA API中找不到这样的function,至少需要一个参数。也许你要调用这个函数

 s = con.createStatement(); 

我只是运行我的代码,用一个Statement实例访问DB2两次,而不是在两个操作之间关闭它。它运行良好。我想你也可以自己尝试一下。

  String sql = ""; String sql2 = ""; String driver = "com.ibm.db2.jcc.DB2Driver"; String url = "jdbc:db2://ip:port/DBNAME"; String user = "user"; String password = "password"; Class.forName(driver).newInstance(); Connection conn = DriverManager.getConnection(url, user, password); Statement statement = conn.createStatement(); ResultSet resultSet = statement.executeQuery(sql); int count = 0; while (resultSet.next()) { count++; } System.out.println("Result row count of query number one is: " + count); count = 0; resultSet = statement.executeQuery(sql2); while (resultSet.next()) { count++; } System.out.println("Result row count of query number two is: " + count);