跳转至

发起查询并处理结果

发起查询并处理结果

任何时候向数据库发出SQL请求时,都需要一个Statement或PreparedStatement实例。 一旦有了Statement或PreparedStatement,就可以用其发起查询。 这将返回一个ResultSet实例,其中包含查询执行的整个结果(如何更改此行为,请查阅“基于游标获取结果”一节)。 示例在JDBC中处理简单查询解释了这个过程。

例 在JDBC中进行简单查询

本示例进行一个简单的查询,并使用Statement打印每行的第一列。

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500");
while (rs.next())
{
    System.out.print("Column 1 returned ");
    System.out.println(rs.getString(1));
}
rs.close();
st.close();

本示例进行相同的查询,但是在查询中使用。

PreparedStatement和并绑定值
int foovalue = 500;
PreparedStatement st = conn.prepareStatement("SELECT * FROM mytable WHERE columnfoo = ?");
st.setInt(1, foovalue);
ResultSet rs = st.executeQuery();
while (rs.next())
{
    System.out.print("Column 1 returned ");
    System.out.println(rs.getString(1));
}
rs.close();
st.close();

根据游标获取结果

默认情况下,驱动程序会一次性获得查询的所有结果。这对于大型结果集可能很不方便,因此JDBC驱动程序提供了基于数据库游标的ResultSet,每次仅获得一小部分数据。

只有少数行被缓存在客户端,当需要更多数据时,可以通过重新定位游标来检索下一块数据。

注意: 基于游标的ResultSet并不是在任何情况都可以使用。有很多限制,这些限制将使驱动程序悄悄的回退一次获得的ResultSet。

  • 与服务器的连接必须使用V3协议,服务器7.4版及更高版本的默认支持,并且仅有7.4及以上支持。

  • 连接不能处于自动提交模式。后端在事务结束时关闭游标,因此自动提交模式下,在获得任何结果之前,后端已经先关闭游标了。

  • 必须使用ResultSet.TYPE_FORWARD_ONLY的ResultSet类型创建该Statement。这是默认设置,因此无需重写任何代码即可利用此功能,但这也意味着您无法向后滚动或在ResultSet中跳来跳去。

  • 给定的查询必须是单个SQL,而不是带有分号的多个语句。

示例 设置获取结果大小以打开和关闭游标

将代码更改为游标模式非常简单,也就是将Statement的获取大小设为适当的数值。 将其设为0会变成客户端缓存所有行(默认行为)。

// make sure autocommit is off
conn.setAutoCommit(false);
Statement st = conn.createStatement();

// Turn use of the cursor on.
st.setFetchSize(50);
ResultSet rs = st.executeQuery("SELECT * FROM mytable");
while (rs.next())
{
    System.out.print("a row was returned.");
}
rs.close();

// Turn the cursor off.
st.setFetchSize(0);
rs = st.executeQuery("SELECT * FROM mytable");
while (rs.next())
{
    System.out.print("many rows were returned.");
}
rs.close();

// Close the statement.
st.close();

使用Statement或PreparedStatement接口

使用Statement或PreparedStatement接口时,必须考虑以下因素:

  • 你可以根据需要多次使用一个Statement实例,在打开连接后立即创建一个连接并将其用于连接的整个生命周期。但是必须记住,整个周期内每个Statement或PreparedStatement只能存在一个ResultSet。

  • 如果在处理ResultSet时需要执行查询,可以创建和使用另一个Statement。

  • 如果你正在使用多线程,并且有几个正在使用数据库,则必须为每个线程使用单独的Statement。

  • 在完成Statement或PreparedStatement的操作后,应将其关闭。

  • 在JDBC中,问号"?"是PreparedStatement的位置参数的占位符。但是,有许多SeaboxSQL操作包含问号,为了避免将SQL语句中的此类问号解释为位置参数,请使用"??"作为转义序列。您也可以在Statement中使用此转义序列,但这不是必需的。特别是仅在语句中,单个"?"可用作运算符。

使用ResultSet接口

使用ResultSet接口时,必须考虑以下因素:

  • 在读取任何值之前,必须调用next()。 如果有结果,则返回true,但更重要的是,它会准备好要处理的行数据。

  • 使用完结果集后,必须通过调用close()关闭它。

  • 一旦重复使用Statement来创建另一个查询的ResultSet,当前的ResultSet实例将自动关闭。

  • 使用PreparedStatement API时,执行五次查询后ResultSet切换到二进制模式(此默认值由prepareThreshold连接属性设置,可能会导致调用某些方法时出现意外的行为。 例如,对非字符串数据类型调用getString()方法,尽管在逻辑上是等效的,但是当执行到设置的prepareThreshold时,如果转换到对象方法转换为与返回模式匹配的一种,则格式可能会有所不同。

执行更新

要更改数据(执行INSERT,UPDATE或DELETE),请使用executeUpdate()方法。 此方法与SELECT语句的executeQuery()类似,但返回的是受INSERT,UPDATE或DELETE语句影响的行数,而不是ResultSet。 例 在JDBC中删除行说明了用法。

示例 在JDBC中删除数据行

本示例将发出一个简单的DELETE语句,并打印出删除的行数。

int foovalue = 500;
PreparedStatement st = conn.prepareStatement("DELETE FROM mytable WHERE columnfoo = ?");
st.setInt(1, foovalue);
int rowsDeleted = st.executeUpdate();
System.out.println(rowsDeleted + " rows deleted");
st.close();

创建和修改数据库对象

要创建,修改或删除数据库对象(如表或视图),请使用execute()方法。 此方法类似于executeQuery(),但不返回结果。 例 在JDBC中删除表说明了用法。

示例 在JDBC中删除表

本示例将删除一个表。

Statement st = conn.createStatement();
st.execute("DROP TABLE mytable");
st.close();

使用Java 8日期和时间类

SeaboxSQL™ JDBC驱动程序内部支持了Java 8 Date and Time API(JSR-310,使用JDBC 4.2)。

表 支持的Java 8日期和时间类

SeaboxSQL Java SE 8
DATE LocalDate
TIME [不带时区] LocalTime
TIMESTAMP [不带时区] LocalDateTime
TIMESTAMP [带时区] OffsetDateTime

这与JDBC 4.2规范中的表B-4和B-5紧密一致。 请注意,不支持ZonedDateTime,Instant和OffsetTime / TIME WITH TIME ZONE。 还要注意,所有OffsetDateTime实例都将采用UTC(偏移量为0)。 这是因为后端将它们存储为UTC。

示例 使用JDBC读取Java 8日期和时间值

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500");
while (rs.next())
{
    System.out.print("Column 1 returned ");
    LocalDate localDate = rs.getObject(1, LocalDate.class));
    System.out.println(localDate);
}
rs.close();
st.close();

对于其他数据类型,只需将其他类传递给#getObject。 请注意,Java数据类型需要与表7.1中的SQL数据类型匹配。

示例 使用JDBC编写Java 8日期和时间值

LocalDate localDate = LocalDate.now();
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, localDate);
st.executeUpdate();
st.close();