13

在 Java 中使用 JDBC 时,普遍接受的查询数据库的方法是获取一个连接,从该连接创建一个语句,然后从该语句执行一个查询。

// load driver
Connection con = DriverManager.getConnection(..);
Statement stmt = con.createStatement();
ResultSet result = stmt.executeQuery("SELECT..");
// ...

但是,我不确定如何处理对同一数据库的第二个查询。

  1. 可以在同一个Statement对象上安全地执行另一个查询,还是必须从该Connection对象创建另一个语句才能执行另一个查询?

  2. 如果同一个Statement对象可以用于多个查询,那么类的目的是什么(因为存在一个方法Statement会更有意义)?Connection.executeQuery()

4

6 回答 6

8

是的,您可以重用该Statement对象,但关闭已打开的结果集ResultSet返回的对象。executeQuery

有关说明,请参见javadoc

默认情况下,每个 Statement 对象只能同时打开一个 ResultSet 对象。因此,如果一个 ResultSet 对象的读取与另一个 ResultSet 对象的读取交错,则每个对象都必须由不同的 Statement 对象生成。Statement 接口中的所有执行方法都会隐式关闭语句的当前 ResultSet 对象(如果存在打开的对象)。

所以会出现以下情况:

// load driver
Connection con = DriverManager.getConnection(..);
Statement stmt = con.createStatement();
ResultSet result = stmt.executeQuery("select ..");
// do something with result ... or not
ResultSet result2 = stmt.executeQuery("select ...");
// result is now closed, you cannot read from it anymore
// do something with result2
stmt.close(); // will close the resultset bound to it

例如,您可以在 jTDS 项目中找到 Statement 的开源实现。在Statement.executeQuery() 方法中,您可以看到initialize()关闭所有已打开的结果集的调用

protected void initialize() throws SQLException {
    updateCount = -1;
    resultQueue.clear();
    genKeyResultSet = null;
    tds.clearResponseQueue();
    // FIXME Should old exceptions found now be thrown instead of lost?
    messages.exceptions = null;
    messages.clearWarnings();
    closeAllResultSets();
}
于 2012-10-18T20:54:10.600 回答
4

以编程方式,您可以对多个查询重复使用相同的连接和相同的语句,并在最后关闭语句和连接。

但是,这不是一个好的做法。应用程序性能对数据库的访问方式非常敏感。理想情况下,每个连接都应该打开尽可能少的时间。然后,必须汇集连接。这样一来,您会将每个查询包含在一个{open connection, create a prepared statement, run query, close statement, close connection}. 这也是大多数 SQL 模板的实现方式。如果并发允许,您可以使用线程池同时触发多个此类查询。

于 2012-10-18T21:03:16.250 回答
2

如果您在线程环境中使用 Connection 和 Statement,我还有一件事要补充。我的经验表明 stmt.executeQuery(..) 可以保存在并行环境中使用,但结果是每个查询都被序列化并因此按顺序处理,不会产生任何加速。所以最好为每个线程使用一个新的连接(而不是语句)。

对于标准的顺序环境,我的经验表明重用语句完全没有问题,结果集不需要手动关闭。

于 2012-10-18T21:28:56.937 回答
1

这就是为什么我们在面向对象编程中有类的概念。一个类定义了使它的实例具有状态和行为的组成成员。这里的语句处理与 sql 语句相关的所有内容。还有更多功能可以执行,例如批量查询等。

于 2012-10-18T20:55:08.180 回答
1

通常,它是一个查询的一个语句。可能没有必要这样做,但是在编写真正的应用程序时,您不想一次又一次地重复这些相同的步骤。这违背了 DRY 原则,而且随着应用程序的增长,它也会变得更加复杂。

编写将处理这种低级(重复)内容的对象,并通过提供查询提供不同的方法来访问数据库是很好的。

于 2012-10-18T21:19:34.347 回答
1

我不会担心创建新的语句。但是,打开数据库连接可能会占用大量资源,并且打开和关闭连接确实会影响性能。

以某种自我管理的方式离开联系通常是非常糟糕的。

您应该考虑使用连接池。您通常会发出关闭突击队,但您只是将该连接返回给池。当您请求新连接时,它将重用您之前提供的连接。

您可能希望对一个连接使用不同的语句。语句是一个实现和一个接口。根据您的需要,您有时需要使用CallableStatment。一些逻辑可以在需要时重用。

于 2012-10-18T21:24:51.350 回答