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个具有不同值的记录。
创建结果集
通过执行Statement
或PreparedStatement
创建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
时,可以设置三个属性。这些是:
- 类型
- 并发
- 可持有性
您在创建Statement
或PreparedStatement
时已经设置了这些,如下所示:
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类型)
方法返回true
或false
,具体取决于是否支持给定的类型。DatabaseMetaData
类将在后面的文本中介绍。
就目前我知道的,有三种ResultSet
类型:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- 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)
方法返回true
或false
,具体取决于是否支持给定的并发模式。DatabaseMetaData
类将在后面进行介绍。
ResultSet
可以具有以下两个并发级别之一:
ResultSet.CONCUR_READ_ONLY
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
是可更新的,也可以在其中插入行
- 调用
ResultSet.moveToInsertRow()
- 更新行-列值
- 调用
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)
返回true
或false
,具体取决于是否支持给定的holdability
模式。DatabaseMetaData
类将在后面的文本中介绍。
holdability有两种类型:
ResultSet.CLOSE_CURSORS_OVER_COMMIT
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