使用单个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设计和文档显示,为多个execute
, executeUpdate
和executeQuery
调用重用Statement
对象是完全正确的(甚至是打算)。 如果不允许在Java文档中明确记录(并且可能API会有所不同)。
此外, Statement
的apidoc说:
Statement
接口中的所有执行方法都隐式关闭一个statment的[ sic ]当前ResultSet
对象(如果存在open对象)。
这表明您可以多次使用它。
TL; DR:是的,您可以多次调用单个Statement
对象上的execute
,只要您意识到之前打开的任何ResultSet
都将被关闭。
您的示例错误地使用了PreparedStatement
,并且您不能(或者:不应该)调用任何接受 PreparedStatement
上的String
的execute...
方法 :
SQLException
– 如果在PreparedStatement
或CallableStatement
该方法
但也要回答PreparedStatement
: PreparedStatement
的全部目的是预编译带参数占位符的语句,并将其重用于具有不同参数值的多次执行。
我在API文档中找不到任何会说明你不应该在给定的PreparedStatement
实例上多次调用executeQuery()
内容。
但是,您的代码不会关闭PreparedStatement
– 对executeQuery()
的调用会在这种情况下抛出SQLException
– 但是executeQuery()
返回的ResultSet
。 重新执行PreparedStatement
时,ResultSet会自动关闭 。 根据您的具体情况,您应该关闭它,当您不再需要它时。 我会关闭它,因为我认为不这样做是不好的。
更新 Upps,我错过了两个试块之间的评论。 如果此时关闭PreparedStatement,则无法在不获取SQLException的情况下再次调用executeQuery()。
Prepared Statement
告诉数据库记住您的查询并准备接受在该查询中执行的参数化变量。 这很像存储过程。
Prepared Statement
完成两件主要的事情:
-
它会自动转义查询变量以防止SQL注入。
-
它告诉数据库记住查询并准备好接受变量。
数字2很重要,因为这意味着数据库只需要解释一次您的查询,然后就可以使用该程序了。 所以它提高了性能。
您不应该在执行调用之间关闭预准备语句和/或数据库连接。 这样做是非常低效的,并且它会比使用普通的旧Statement
带来更多的开销,因为每次指示数据库创建一个过程并记住它。 即使数据库配置为“热点”并且即使您关闭PreparedStatement
仍然会记住您的查询,您仍然会产生网络开销以及较小的处理时间。
简而言之,保持Connection
和PreparedStatement
打开,直到完成它们为止。
编辑:要注释不从执行中返回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);