JDBC ResultSet

JDBC ResultSet

  • ResultSet包含记录

  • 创建ResultSet

    • ResultSet类型、并发性和可保持性
  • 迭代ResultSet

  • 访问列值

  • ResultSet类型

    • 导航方法
  • ResultSet并发

  • 更新ResultSet

  • 将行插入ResultSet中

  • ResultSet可保持性

Java JDBC ResultSet接口表示数据库查询的结果。关于查询的文本显示了如何将查询的结果作为java.sql.ResultSet返回。然后迭代此ResultSet以检查结果。本教程介绍如何使用ResultSet接口。

结果集包含记录

JDBC ResultSet包含记录。每条记录都包含一组列。每个记录包含相同数量的列,尽管并非所有列都有一个值。列可以具有null值。以下是JDBC ResultSet的示例:

Name Age
张三 22
李四 23
王五 25

ResultSet示例-带列的记录

ResultSet有2个不同的列(Name、Age),每列有3个具有不同值的记录。

创建结果集

通过执行StatementPreparedStatement创建ResultSet,如下所示:

java 复制代码
Statement statement = connection.createStatement();

ResultSet result = statement.executeQuery("select * from test");

或者像这样:

java 复制代码
String sql = "select * from test";
PreparedStatement statement = connection.prepareStatement(sql);

ResultSet result = statement.executeQuery();

ResultSet类型、并发性和可保持性

创建 ResultSet时,可以设置三个属性。这些是:

  1. 类型
  2. 并发
  3. 可持有性

您在创建StatementPreparedStatement时已经设置了这些,如下所示:

java 复制代码
Statement statement = connection.createStatement(
    ResultSet.TYPE_FORWARD_ONLY,
    ResultSet.CONCUR_READ_ONLY,
    ResultSet.CLOSE_CURSORS_OVER_COMMIT
   );

PreparedStatement statement = connection.prepareStatement(sql,
    ResultSet.TYPE_FORWARD_ONLY,
    ResultSet.CONCUR_READ_ONLY,
    ResultSet.CLOSE_CURSORS_OVER_COMMIT
   );

这些属性的确切含义将在本文后面解释。

迭代ResultSet

要迭代ResultSet,可以使用它的next()方法。如果ResultSet有下一条记录,则next()方法返回true,并将ResultSet移动到下一个记录。如果没有更多的记录,next()将返回false,您就不能再这样做了。一旦next()方法返回false,就不应该再调用它了。否则这样做可能会导致异常。

以下是使用next()方法迭代ResultSet的示例:

java 复制代码
while(result.next()) {
    // result.getString("name")
}

正如您所看到的,next()方法实际上是在访问第一条记录之前调用的。这意味着ResultSet开始指向第一条记录之前。一旦next()被调用一次,它就会指向第一条记录。

类似地,当next()被调用并返回false时,ResultSet实际上指向最后一条记录之后。

除非您对ResultSet中的所有行进行迭代并对行数进行计数,否则无法获得结果集中的行数。但是,如果ResultSet仅向前,则以后不能向后移动。即使可以向后移动,这也是计算ResultSet中行数的缓慢方法。你最好构建你的代码,这样你就不需要提前知道记录的数量。

访问列值

迭代ResultSet时,您希望访问每条记录的列值。您可以通过调用许多getXXX()方法中的一个或多个来实现这一点。将要获取的值的列的名称传递给许多getXXX()方法。例如:

java 复制代码
while(result.next()) {

    result.getString    ("name");
    result.getInt       ("age");
    result.getBigDecimal("money");
   
}

你可以调用很多getXXX()方法,它们以某种数据类型返回列的值,例如String、int、long、double、BigDecimal等。它们都以列的名称来获取的列值作为参数。以下是这些getXXX()方法的快速示例列表:

java 复制代码
result.getArray("columnName");
result.getAsciiStream("columnName");
result.getBigDecimal("columnName");
result.getBinaryStream("columnName");
result.getBlob("columnName");
result.getBoolean("columnName");
result.getBlob("columnName");
result.getBoolean("columnName");
result.getByte("columnName");
result.getBytes("columnName");
result.getCharacterStream("columnName");
result.getClob("columnName");
result.getDate("columnName");
result.getDouble("columnName");
result.getFloat("columnName");
result.getInt("columnName");
result.getLong("columnName");
result.getNCharacterStream("columnName");
result.getObject("columnName");
result.getRef("columnName");
result.getRowId("columnName");
result.getShort("columnName");
result.getSQLXML("columnName");
result.getString("columnName");
result.getTime("columnName");
result.getTimestamp("columnName");
result.getUnicodeStream("columnName");
result.getURL("columnName");

getXXX()方法也有采用列索引而不是列名的版本。例如:

java 复制代码
while(result.next()) {

    result.getString    (1);
    result.getInt       (2);
    result.getBigDecimal(3);
}

列的索引通常取决于SQL语句中该列的索引。例如,SQL语句

sql 复制代码
select name, age, money from test

有三列。name列在第一位,因此在ResultSet中将具有索引1。age列将具有索引2,money列将具有索引3。

有时你不知道某一列的索引提前。例如,如果使用select * from test类型的SQL查询,则不知道列的顺序。

如果你不知道某一列的索引,你可以使用ResultSet.findColum(StringcolumnName)方法找到该列的索引

java 复制代码
int nameIndex   = result.findColumn("name");
int ageIndex    = result.findColumn("age");
int coeffIndex  = result.findColumn("money");

while(result.next()) {
    String     name        = result.getString(nameIndex);
    int        age         = result.getInt(ageIndex);
    BigDecimal money       = result.getBigDecimal(money);
}

ResultSet类型

ResultSet可以是特定类型的。类型决定了ResultSet的一些特性和能力。

并非所有数据库和JDBC驱动程序都支持所有类型。您必须检查数据库和JDBC驱动程序,看看它是否支持您想要使用的类型。DatabaseMetaData.supportsResultSetType(int类型)方法返回truefalse,具体取决于是否支持给定的类型。DatabaseMetaData类将在后面的文本中介绍。

就目前我知道的,有三种ResultSet类型:

  1. ResultSet.TYPE_FORWARD_ONLY
  2. ResultSet.TYPE_SCROLL_INSENSITIVE
  3. ResultSet.TYPE_SCROLL_SENSITIVE

默认类型为TYPE_FORWARD_ONLY

TYPE_FORWARD_ONLY表示只能向前导航ResultSet。也就是说,您只能从第1行移动到第2行、第3行等。您不能在ResultSet中向后移动。

TYPE_SCROLL_INSENSITIVE表示可以向前和向后导航(滚动)ResultSet。也可以跳到相对于当前位置的位置,或者跳到绝对位置。当ResultSet处于打开状态时,ResultSet对基础数据源中的更改不敏感。也就是说,如果另一个线程或进程在数据库中更改了ResultSet中的记录,它将不会反映在已打开的此类ResultSet中。

TYPE_SCROLL_SENSITIVE表示可以向前和向后导航(滚动)ResultSet。也可以跳到相对于当前位置的位置,或者跳到绝对位置。当ResultSet处于打开状态时,ResultSet对基础数据源中的更改很敏感。也就是说,如果数据库中的ResultSet中的记录被另一个线程或进程更改,它将反映在已打开的此类ResultSet中。

导航方法

ResultSet接口包含以下导航方法。请记住,并非所有方法都适用于所有ResultSet类型。什么方法有效取决于您的数据库、JDBC驱动程序和ResultSet类型。

方法 描述
absolute() 将ResultSet移动到绝对位置。位置是作为参数传递给absolute()方法的行号
afterLast() 将ResultSet移动到ResultSet中最后一行的后面
beforeFirst() 将ResultSet移动到ResultSet的第一行之前
first() 将ResultSet移动到ResultSet中的第一行
last() 将ResultSet移动到ResultSet中的最后一行
next() 将ResultSet移动到ResultSet中的下一行
previous() 将结果集移动到结果集中的前一行
relative() 将ResultSet移动到相对于其当前位置的位置。相对位置作为参数传递给相对方法,可以是正的也可以是负的
移动结果集

ResultSet接口还包含一组方法,可用于查询ResultSet的当前位置。这些是:

方法 描述
getRow() 返回当前行的行号-ResultSet当前指向的行
getType() 返回ResultSet类型
isAfterLast() 如果ResultSet指向最后一行之后,则isAfterLast()返回true。否则为False
isBeforeFirst() 如果ResultSet指向最后一行之后,则返回true。否则为False
isFirst() 如果ResultSet指向第一行之前,则返回true。否则为False

ResultSet接口还包含一个方法,用于在ResultSet对更改敏感的情况下,通过数据库更改来更新行。

方法 描述
refreshRow() 使用数据库中的最新值刷新该行的列值

ResultSet并发

ResultSet并发性决定了ResultSet是可以更新还是只能读取。

某些数据库和JDBC驱动程序支持更新ResultSet,但并非所有数据库和JDBC驱动器都支持。DatabaseMetaData.supportsResultSetConcurrency(intconcurrency)方法返回truefalse,具体取决于是否支持给定的并发模式。DatabaseMetaData类将在后面进行介绍。

ResultSet可以具有以下两个并发级别之一:

  1. ResultSet.CONCUR_READ_ONLY
  2. ResultSet.CONCUR_UPDABLE

CONCUR_READ_ONLY表示只能读取ResultSet

CONCUR_UPDABLE表示ResultSet既可以读取也可以更新。

更新ResultSet

如果ResultSet是可更新的,则可以更新结果集中每一行的列。您可以使用许多updateXXX()方法来完成此操作。例如:

java 复制代码
    result.updateString     ("name"       , "tianjh");
    result.updateInt        ("age"        , 26);
    result.updateBigDecimal ("money", new BigDecimal("100.0001");
    result.updateRow();

也可以使用列索引而不是列名来更新列。如下示例:

java 复制代码
    result.updateString     (1, "tianjh");
    result.updateInt        (2, 26);
    result.updateBigDecimal (3, new BigDecimal("100.0001");
    result.updateRow();

请注意要使用updateRow() 调用。只有在调用updateRow() 时,数据库才会使用该行的值进行更新。如果您不调用此方法,则ResultSet中更新的值永远不会发送到数据库。如果在事务内部调用updateRow() ,那么在事务提交之前,数据实际上不会提交到数据库。

将行插入ResultSet中

如果ResultSet是可更新的,也可以在其中插入行

  1. 调用ResultSet.moveToInsertRow()
  2. 更新行-列值
  3. 调用ResultSet.insertRow()

以下是一个示例:

java 复制代码
result.moveToInsertRow();
result.updateString     (1, "tianjh");
result.updateInt        (2, 26);
result.updateBigDecimal (3, new BigDecimal("100.0001");
result.insertRow();

result.beforeFirst();

调用moveToInsertRow()后指向的行是一个特殊的行,一个缓冲区,您可以使用它来构建该行,直到该行上设置了所有列值。

一旦该行准备好插入ResultSet,就调用insertRow()方法。

插入行后,ResultSet仍指向插入行。但是,一旦插入该行,您无法确定如果尝试访问它会发生什么。因此,您应该在插入新行后将ResultSet移动到有效位置。如果需要插入另一行,请显式调用moveToInsertRow()以向ResultSet发出信号。

ResultSet可保持性

ResultSet的可保持性决定调用底层连接的commit()方法时是否关闭ResultSet

并非所有数据库和JDBC驱动程序都支持所有的可保持模式。DatabaseMetaData.supportsResultSetHoldability(int holdability)返回truefalse,具体取决于是否支持给定的holdability模式。DatabaseMetaData类将在后面的文本中介绍。

holdability有两种类型:

  1. ResultSet.CLOSE_CURSORS_OVER_COMMIT
  2. ResultSet.HOLD_CURSORS_OVER_COMMIT

CLOSE_CURSORS_OVER_COMMIT可保持性意味着当对创建ResultSet的连接调用connection.commit()方法时,所有ResultSet实例都将关闭。

HOLD_CURSORS_OVER_COMMIT可保持性意味着在创建ResultSet的连接上调用connection.commit()方法时,ResultSet保持打开状态。

如果使用ResultSet更新数据库中的值,那么HOLD_CURSORS_OVER_COMMIT保持能力可能会很有用。因此,您可以打开ResultSet,更新其中的行,调用connection.commit(),并且仍然为同一行上的未来事务打开相同的ResultSet

下一篇:JDBC PreparedStatement

相关推荐
刘大浪11 分钟前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
无敌岩雀18 分钟前
MySQL中的索引
数据库·mysql
a_安徒生40 分钟前
linux安装TDengine
linux·数据库·tdengine
程序员学习随笔43 分钟前
PostgreSQL技术内幕19:逻辑备份工具pg_dump、pg_dumpall
数据库·postgresql
尘浮生1 小时前
Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
偶尔。5351 小时前
什么是事务?事务有哪些特性?
数据库·oracle
安迁岚1 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验六 视图
数据库·sql·mysql·oracle·实验报告
喵叔哟1 小时前
16. 【.NET 8 实战--孢子记账--从单体到微服务】--汇率获取定时器
微服务·oracle·.net
xoxo-Rachel1 小时前
(超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化
java·数据库·mysql
JH30732 小时前
Oracle与MySQL中CONCAT()函数的使用差异
数据库·mysql·oracle