2. 概述
本文将深入探讨JDBC中的RowSet
接口。与传统的ResultSet
相比,RowSet
对象以更灵活、更易用的方式持有表格数据。
Oracle为最常见的RowSet
使用场景定义了五种实现:
JdbcRowSet
CachedRowSet
WebRowSet
JoinRowSet
FilteredRowSet
接下来我们将逐一解析这些接口的使用方法。
3. JdbcRowSet
先从JdbcRowSet
开始。创建时只需设置数据库连接的URL、用户名和密码:
JdbcRowSet jdbcRS = RowSetProvider.newFactory().createJdbcRowSet();
jdbcRS.setUrl("jdbc:h2:mem:testdb");
jdbcRS.setUsername("sa");
jdbcRS.setPassword("");
jdbcRS.setType(ResultSet.TYPE_SCROLL_INSENSITIVE);
String sql = "SELECT * FROM customers";
jdbcRS.setCommand(sql);
jdbcRS.execute();
jdbcRS.addRowSetListener(new ExampleListener());
while (jdbcRS.next()) {
// 每次调用next都会触发cursorMoved事件
System.out.println("id = " + jdbcRS.getString(1));
System.out.println("name = " + jdbcRS.getString(2));
}
⚠️ 注意:在调用setCommand
方法定义SQL语句并执行execute
方法前,jdbcRS
对象中是没有数据的。
另外,为了处理事件,我们给JdbcRowSet
添加了RowSetListener
监听器。
JdbcRowSet
与其他四种实现的核心区别在于:它始终与数据库保持连接,因此与ResultSet
对象最为相似。
4. CachedRowSet
CachedRowSet
的独特之处在于它可以在不连接数据源的情况下工作,我们称之为"离线RowSet
对象"。
它得名于其将数据缓存在内存中的特性,使其能直接操作内存数据而非数据库数据。
由于CachedRowSet
是所有离线RowSet对象的超接口,以下代码同样适用于WebRowSet
、JoinRowSet
或FilteredRowSet
:
CachedRowSet crs = RowSetProvider.newFactory().createCachedRowSet();
crs.setUsername(username);
crs.setPassword(password);
crs.setUrl(url);
crs.setCommand(sql);
crs.execute();
crs.addRowSetListener(new ExampleListener());
while (crs.next()) {
if (crs.getInt("id") == 1) {
System.out.println("CRS找到customer1记录,将删除该行");
crs.deleteRow();
break;
}
}
5. WebRowSet
接下来看WebRowSet
。它的独特之处在于:除了具备CachedRowSet
的所有功能外,还能将自身写入XML文档,并从XML文档读取数据恢复为WebRowSet
对象:
WebRowSet wrs = RowSetProvider.newFactory().createWebRowSet();
wrs.setUsername(username);
wrs.setPassword(password);
wrs.setUrl(url);
wrs.setCommand(sql);
wrs.execute();
FileOutputStream ostream = new FileOutputStream("customers.xml");
wrs.writeXml(ostream);
通过writeXml
方法,我们将WebRowSet
对象的当前状态写入XML文档。传入OutputStream
对象可以字节方式写入,这对处理各类数据特别实用。
6. JoinRowSet
JoinRowSet
允许我们在内存中对多个RowSet
对象执行SQL JOIN操作,无需创建数据库连接,省去了连接开销:
CachedRowSet customers = RowSetProvider.newFactory().createCachedRowSet();
// 配置customers的CachedRowSet设置
CachedRowSetImpl associates = new CachedRowSetImpl();
// 配置associates的CachedRowSet设置
JoinRowSet jrs = new JoinRowSetImpl();
jrs.addRowSet(customers, "ID");
jrs.addRowSet(associates, "ID");
每个加入JoinRowSet
的对象都需要指定匹配列(即SQL JOIN的依据列),我们在addRowSet
方法中指定了"id"
列。
✅ 提示:除了使用列名,也可以使用列号(如addRowSet(customers, 1)
)。
7. FilteredRowSet
最后是FilteredRowSet
,它能过滤RowSet
中可见的行数,让我们只关注当前任务相关的数据。
通过实现Predicate
接口来定义过滤逻辑:
public class FilterExample implements Predicate {
private Pattern pattern;
public FilterExample(String regexQuery) {
if (regexQuery != null && !regexQuery.isEmpty()) {
pattern = Pattern.compile(regexQuery);
}
}
public boolean evaluate(RowSet rs) {
try {
if (!rs.isAfterLast()) {
String name = rs.getString("name");
System.out.println(String.format(
"正在用模式'%s'匹配 %s", pattern.toString(),
name));
Matcher matcher = pattern.matcher(name);
return matcher.matches();
} else
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 错误处理方法
}
将过滤器应用到FilteredRowSet
对象:
RowSetFactory rsf = RowSetProvider.newFactory();
FilteredRowSet frs = rsf.createFilteredRowSet();
frs.setCommand("select * from customers");
frs.execute(conn);
frs.setFilter(new FilterExample("^[A-C].*"));
ResultSetMetaData rsmd = frs.getMetaData();
int columncount = rsmd.getColumnCount();
while (frs.next()) {
for (int i = 1; i <= columncount; i++) {
System.out.println(
rsmd.getColumnLabel(i)
+ " = "
+ frs.getObject(i) + " ");
}
}
8. 总结
本文快速解析了JDK中五种标准的RowSet
接口实现:
JdbcRowSet
:唯一保持连接的实现CachedRowSet
:基础离线实现WebRowSet
:支持XML序列化JoinRowSet
:内存JOIN操作FilteredRowSet
:数据行过滤
所有代码示例可在GitHub仓库获取完整版。