ResultSet (结果集)
RSType 和 RSConcurrency
当对数据库进行查询操作的时候, 数据库返回的数据通过 ResultSet 接口获取. ResultSet 内部管理了一个 cursor(游标), cursor 指向当前要读的数据, ResultSet 提供了以下三类接口:
- 游标移动接口, 用来操作移动游标.
- 获取数据接口, 用来从当前游标指向位置的数据
- 更新数据接口, 用来更新当前游标指向位置的数据, 并可以更改对应数据库中的数据.
ResultSet 的类型:
在创建 Statement 的时候, 可以添加两个参数.
createStatement(int RSType, int RSConcurrency);
prepareStatement(String SQL, int RSType, int RSConcurrency);
prepareCall(String sql, int RSType, int RSConcurrency);
其中第一个参数RSType
主要描述两件事:
- Cusor 是否可以前后移动
- 已经取出的结果集对数据库的改动是否需要更新
RSType
的值可以取下面三个:
ResultSet.TYPE_FORWARD_ONLY
: Cursor 只能往前移动, 默认值ResultSet.TYPE_SCROLL_INSENSITIVE
: Cursor 可以前后移动, 但是对于数据库的改动不关心.ResultSet.TYPE_SCROLL_SENSITIVE
: Cursor 可以前后移动, 并且当数据库发生改动的时候, ResultSet也会随之更新.
RSConcurrency
用来描述我们是否可以更新结果集中的数据到数据库. 有两个值可以用:
ResultSet.CONCUR_READ_ONLY
: 结果集是只读的ResultSet.CONCUR_UPDATABLE
: 结果集是可以更新的.
注意, 并不是所有的数据库都支持这些类型, 可以查看数据库驱动的支持情况:
public static void printResultSetSupport(Connection conn) {
DatabaseMetaData md = null;
try {
md = conn.getMetaData();
// Verify ResultSet‘s type
System.out.println("Supports TYPE_FORWARD_ONLY: " + md.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY));
System.out.println("Supports TYPE_SCROLL_INSENSITIVE: " + md.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE));
System.out.println("Supports TYPE_SCROLL_SENSITIVE: " + md.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));
// Verify ResultSet‘s concurrency
System.out.println("Supports CONCUR_READ_ONLY for TYPE_FORWARD_ONLY: " + md.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY));
System.out.println("Supports CONCUR_UPDATABLE for TYPE_FORWARD_ONLY: " + md.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE));
System.out.println("Supports CONCUR_READ_ONLY for TYPE_SCROLL_INSENSITIVE: " + md.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY));
System.out.println("Supports CONCUR_UPDATABLE for TYPE_SCROLL_INSENSITIVE: " + md.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE));
System.out.println("Supports CONCUR_READ_ONLY for TYPE_SCROLL_SENSITIVE: " + md.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY));
System.out.println("Supports CONCUR_UPDATABLE for TYPE_SCROLL_SENSITIVE: " + md.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE));
} catch(SQLException e) {
printSQLException(e);
}
}
MySQL 的执行结果如下:
Supports TYPE_FORWARD_ONLY: false
Supports TYPE_SCROLL_INSENSITIVE: true
Supports TYPE_SCROLL_SENSITIVE: false
Supports CONCUR_READ_ONLY for TYPE_FORWARD_ONLY: true
Supports CONCUR_UPDATABLE for TYPE_FORWARD_ONLY: true
Supports CONCUR_READ_ONLY for TYPE_SCROLL_INSENSITIVE: true
Supports CONCUR_UPDATABLE for TYPE_SCROLL_INSENSITIVE: true
Supports CONCUR_READ_ONLY for TYPE_SCROLL_SENSITIVE: false
Supports CONCUR_UPDATABLE for TYPE_SCROLL_SENSITIVE: false
__ 我在测是的时候, 发现 MySQL 默认的 Cursor 竟然也可以往前往后移动! 难道 MySQL 默认的是 TYPE_SCROLL_INSENSITIVE
?
其实, 不是的, MYSQL 会缓存结果集, 导致默认类型的 TYPE_FORWARD_ONLY
升级成了可以前后移动的. 只要我们调整一下将结果集的缓存设为最小, cursor 的行为就正常了:
tatement s = dbConnection.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
s.setFetchSize(Integer.MIN_VALUE);
更多解释请看此链接 __
JavaDB 的执行结果如下:
Supports TYPE_FORWARD_ONLY: true
Supports TYPE_SCROLL_INSENSITIVE: true
Supports TYPE_SCROLL_SENSITIVE: false
Supports CONCUR_READ_ONLY for TYPE_FORWARD_ONLY: true
Supports CONCUR_UPDATABLE for TYPE_FORWARD_ONLY: true
Supports CONCUR_READ_ONLY for TYPE_SCROLL_INSENSITIVE: true
Supports CONCUR_UPDATABLE for TYPE_SCROLL_INSENSITIVE: true
Supports CONCUR_READ_ONLY for TYPE_SCROLL_SENSITIVE: false
Supports CONCUR_UPDATABLE for TYPE_SCROLL_SENSITIVE: false
Cursor Holdability
关于 Cursor 其实还有一个属性, 是关于事务提交后, 是否需要关闭结果集的问题. 相关 API 为:
conn.setHoldability();
来改变这种行为, 可以传入的参数有:
HOLD_CURSORS_OVER_COMMIT
: 当调用Connection.commit()
后, ResultSet 将不会关闭, 一般用于只读的结果集中.CLOSE_CURSORS_AT_COMMIT
: 当调用Connection.commit()
后, ResultSet 将会关闭.
JDBC 没有规定默认的值, 但是有相应的 API 来获取默认值以及支持情况:
public static void printCursorHoldability(Connection conn) throws SQLException {
DatabaseMetaData md = conn.getMetaData();
System.out.println("-- ResultSet Cursor Holdability --");
int holdability = md.getResultSetHoldability();
if (holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
System.out.println("Default: CLOSE_CURSORS_AT_COMMIT");
} else if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
System.out.println("Default: ResultSet.HOLD_CURSORS_OVER_COMMIT");
}
System.out.println("Supports CLOSE_CURSORS_AT_COMMIT: "
+ md.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT));
System.out.println("Supports HOLD_CURSORS_OVER_COMMIT: "
+ md.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT));
}
MySQL 结果是:
-- ResultSet Cursor Holdability --
Default: ResultSet.HOLD_CURSORS_OVER_COMMIT
Supports CLOSE_CURSORS_AT_COMMIT: false
Supports HOLD_CURSORS_OVER_COMMIT: true
而 JavaDB 的结果是:
-- ResultSet Cursor Holdability --
Default: ResultSet.HOLD_CURSORS_OVER_COMMIT
Supports CLOSE_CURSORS_AT_COMMIT: true
Supports HOLD_CURSORS_OVER_COMMIT: true
时间: 2024-10-20 07:22:33