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

时间:2014-01-24 07:38:13

标签: java mysql sql jdbc

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

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

E.G:

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);
}

5 个答案:

答案 0 :(得分:22)

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

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

答案 1 :(得分:9)

我不确定你为什么这么问。 API设计和文档显示,对多个StatementexecuteexecuteUpdate调用重用executeQuery对象是完全正确的(甚至是预期的)。如果不允许在Java文档中明确记录(可能API会有所不同)。

此外,Statement的apidoc说:

  

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

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

TL; DR:是的,您可以多次在单个execute对象上致电Statement,只要您发现任何先前打开的ResultSet将被关闭。

您的示例错误地使用了PreparedStatement,您不能(或者:不应该)调用PreparedStatement上的任何execute... methods accepting a String

  

SQLException - 如果在PreparedStatementCallableStatement上调用方法

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

答案 2 :(得分:4)

我在API docs中找不到任何可以说明您不应在给定executeQuery()个实例上多次调用PreparedStatement的内容。

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

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

答案 3 :(得分:3)

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

Prepared Statement完成两件事:

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

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

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

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

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

    编辑:要评论没有从执行中返回ResultSet,这很好。对于刚刚执行的查询,executeQuery将返回ResultSet

答案 4 :(得分:1)

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

s = con.prepareStatement();

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

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);