#处理结果集
ResultSet对象表示数据库查询返回的结果集。应用程序通过ResultSet游标逐行读取查询结果,也可以根据创建Statement时指定的类型和并发模式,使用可滚动或可更新结果集。
本文示例使用如下测试表和数据。实际使用时,请将连接地址、用户名和密码替换为目标环境的配置。
CREATE TABLE jdbc_resultset_customer (
customer_id INTEGER PRIMARY KEY,
customer_name VARCHAR(50),
credit_limit DECIMAL(10, 2),
created_date DATE
);
示例数据包含5条客户记录,用于演示结果集遍历、游标定位和行更新。示例程序会自动创建和删除测试表。
为减少重复代码,以下Java示例使用ResultSetTestSupport完成驱动加载、数据库连接、测试表初始化和清理。该类仅用于文档示例,不属于YashanDB JDBC API;实际项目中请替换为应用程序已有的连接和数据准备逻辑。
package quickstart;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Properties;
final class ResultSetTestSupport {
static final String TABLE = "jdbc_resultset_customer";
private static final String URL =
"jdbc:yasdb://192.168.1.2:1688/yasdb";
private ResultSetTestSupport() {
}
static Connection openConnection() throws Exception {
Class.forName("com.yashandb.jdbc.Driver");
Properties properties = new Properties();
properties.setProperty("user", "username");
properties.setProperty("password", "passwd");
return DriverManager.getConnection(URL, properties);
}
static void prepareTable() throws Exception {
try (Connection connection = openConnection();
Statement statement = connection.createStatement()) {
statement.execute("DROP TABLE IF EXISTS " + TABLE);
statement.execute(
"CREATE TABLE " + TABLE
+ " (customer_id INTEGER PRIMARY KEY, "
+ "customer_name VARCHAR(50), "
+ "credit_limit DECIMAL(10, 2), "
+ "created_date DATE)");
for (int id = 1; id <= 5; id++) {
statement.executeUpdate(
"INSERT INTO " + TABLE + " VALUES ("
+ id + ", 'Customer " + id + "', "
+ (id * 1000) + ".00, "
+ "DATE '2026-01-0" + id + "')");
}
}
}
static void dropTable() throws Exception {
try (Connection connection = openConnection();
Statement statement = connection.createStatement()) {
statement.execute("DROP TABLE IF EXISTS " + TABLE);
}
}
}
# 创建和读取ResultSet
# 创建ResultSet
调用Statement.executeQuery()执行查询即可创建ResultSet。ResultSet、Statement和Connection都实现了AutoCloseable,可以使用try-with-resources按资源依赖关系自动关闭。
以下示例查询指定客户,并通过next()将游标移动到第一行后读取列值。
package quickstart;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class ResultSetCreationExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try (Connection connection = ResultSetTestSupport.openConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT customer_id, customer_name FROM "
+ ResultSetTestSupport.TABLE
+ " WHERE customer_id = 1")) {
if (resultSet.next()) {
System.out.println(
"Customer: " + resultSet.getInt("customer_id")
+ ", "
+ resultSet.getString("customer_name"));
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
Customer: 1, Customer 1
# 遍历结果集
next()每调用一次,游标向前移动一行。当没有更多数据时返回false。列可以通过从1开始的列索引或列标签读取。
以下示例使用列索引读取客户编号,使用列标签读取客户名称,并遍历全部5条记录。
package quickstart;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class ResultSetTraversalExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try (Connection connection = ResultSetTestSupport.openConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT customer_id, customer_name FROM "
+ ResultSetTestSupport.TABLE
+ " ORDER BY customer_id")) {
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString("customer_name");
System.out.println("Customer: " + id + ", " + name);
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
Customer: 1, Customer 1
Customer: 2, Customer 2
Customer: 3, Customer 3
Customer: 4, Customer 4
Customer: 5, Customer 5
# 检索不同类型的数据
ResultSet提供了与数据库类型对应的getXxx()方法。读取数据时,应选择与列类型匹配的方法;例如使用getInt()读取整数、getString()读取字符、getBigDecimal()读取精确数值、getDate()读取日期。
以下示例读取客户编号、名称、额度和创建日期四种类型的列。
package quickstart;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.Statement;
public class ResultSetDataTypesExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try (Connection connection = ResultSetTestSupport.openConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT customer_id, customer_name, credit_limit, "
+ "created_date FROM "
+ ResultSetTestSupport.TABLE
+ " WHERE customer_id = 1")) {
if (resultSet.next()) {
int id = resultSet.getInt("customer_id");
String name = resultSet.getString("customer_name");
java.math.BigDecimal creditLimit =
resultSet.getBigDecimal("credit_limit");
Date createdDate = resultSet.getDate("created_date");
System.out.println(
id + ", " + name + ", " + creditLimit
+ ", " + createdDate);
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
1, Customer 1, 1000, 2026-01-01
# 可滚动结果集
创建Statement时指定ResultSet.TYPE_SCROLL_INSENSITIVE,可以使用first()、last()、absolute()、relative()和previous()等方法移动游标。ResultSet.CONCUR_READ_ONLY表示结果集只读。
以下示例演示从结果集末尾、开头和指定行之间移动游标。示例使用5条测试数据,因此absolute(5)定位到第五行。
package quickstart;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class ScrollableResultSetExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try (Connection connection = ResultSetTestSupport.openConnection();
Statement statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet resultSet = statement.executeQuery(
"SELECT customer_id, customer_name FROM "
+ ResultSetTestSupport.TABLE
+ " ORDER BY customer_id")) {
if (resultSet.last()) {
System.out.println("Total rows: " + resultSet.getRow());
}
if (resultSet.first()) {
System.out.println(
"First customer: "
+ resultSet.getString("customer_name"));
}
if (resultSet.absolute(5)) {
System.out.println(
"Fifth customer: "
+ resultSet.getString("customer_name"));
}
if (resultSet.relative(-2)) {
System.out.println(
"Third customer: "
+ resultSet.getString("customer_name"));
}
if (resultSet.previous()) {
System.out.println(
"Previous customer: "
+ resultSet.getString("customer_name"));
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
Total rows: 5
First customer: Customer 1
Fifth customer: Customer 5
Third customer: Customer 3
Previous customer: Customer 2
# 可更新结果集
创建Statement时指定ResultSet.CONCUR_UPDATABLE,可以通过updateXxx()写入当前行的临时值,再调用updateRow()将修改提交到数据库。应用程序仍需要根据事务配置调用commit()或rollback()。
以下示例将编号为1的客户名称更新为Updated customer。执行更新前关闭自动提交,确认结果后提交事务;发生异常时回滚。
package quickstart;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class UpdatableResultSetExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try (Connection connection = ResultSetTestSupport.openConnection()) {
connection.setAutoCommit(false);
try (Statement statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet = statement.executeQuery(
"SELECT customer_id, customer_name FROM "
+ ResultSetTestSupport.TABLE)) {
while (resultSet.next()) {
if (resultSet.getInt("customer_id") == 1) {
resultSet.updateString(
"customer_name", "Updated customer");
resultSet.updateRow();
break;
}
}
connection.commit();
} catch (Exception exception) {
connection.rollback();
throw exception;
}
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT customer_name FROM "
+ ResultSetTestSupport.TABLE
+ " WHERE customer_id = 1")) {
resultSet.next();
System.out.println(
"Updated name: " + resultSet.getString(1));
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
Updated name: Updated customer
# ResultSet元数据
ResultSetMetaData用于读取结果集的结构信息,适合列数量或列结构在运行时才确定的场景。常用方法包括getColumnCount()、getColumnLabel()和getColumnTypeName()。
以下示例读取查询结果的列数、列标签和数据库类型名称。
package quickstart;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class ResultSetMetaDataExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try (Connection connection = ResultSetTestSupport.openConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT customer_id, customer_name, credit_limit FROM "
+ ResultSetTestSupport.TABLE)) {
ResultSetMetaData metadata = resultSet.getMetaData();
System.out.println("Column count: " + metadata.getColumnCount());
for (int index = 1;
index <= metadata.getColumnCount();
index++) {
System.out.println(
metadata.getColumnLabel(index)
+ ": "
+ metadata.getColumnTypeName(index));
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
Column count: 3
CUSTOMER_ID: INTEGER
CUSTOMER_NAME: VARCHAR
CREDIT_LIMIT: NUMBER
# 资源管理
ResultSet使用完毕后应及时关闭,同时关闭创建它的Statement和数据库连接。推荐使用try-with-resources,关闭顺序由Java运行时按声明顺序的逆序处理,避免结果集、语句或连接长期占用资源。
以下示例遍历结果集后退出try代码块,自动关闭ResultSet、Statement和Connection。
package quickstart;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class ResourceManagementExample {
public static void main(String[] args) throws Exception {
ResultSetTestSupport.prepareTable();
try {
try (Connection connection =
ResultSetTestSupport.openConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT customer_name FROM "
+ ResultSetTestSupport.TABLE
+ " ORDER BY customer_id")) {
while (resultSet.next()) {
System.out.println(
"Customer: " + resultSet.getString(1));
}
}
} finally {
ResultSetTestSupport.dropTable();
}
}
}
正常情况下,程序输出如下:
Customer: Customer 1
Customer: Customer 2
Customer: Customer 3
Customer: Customer 4
Customer: Customer 5

