根据JDK JDBC文档,ResultSet::setFetchSize()函数语义为 JDBC 驱动程序设置此 ResultSet 对象需要更多行时应该从数据库获取的行数。如果指定的获取大小为零,则 JDBC 驱动程序忽略该值,随意对获取大小作出它自己的最佳猜测。默认值由创建结果集的 Statement 对象设置。获取大小可以在任何时间更改。
但在实际使用Oracle JDBC驱动时,我们开发的程序发生了莫名的错误,总是会出现获取到的取值与数据库实际取值不一致的情形,经过仔细的测试与排查,我们发现是由于ResultSet::setFetchSize()函数调用导致的错误,在我们的测试环境中,Oracle JDBC缺省为ResultSet设定的大小为10,如果我们将其改编为100,那么一般会在获取第11条记录的第一个取值时发生获得取值与数据库实际取值不一致的问题,引发问题的语句如下:
ResultSet equipRs = roleStat.executeQuery();
if(equipRs.getFetchSize() < 20)
equipRs.setFetchSize(20);
但如果我们调用Statement的setFetchSize()函数预先设置FetchSize为期望的值,则不会引发问题:
roleStat.setFetchSize(20); // 调用Statement的setFetchSize()方法不会引发问题
ResultSet equipRs = roleStat.executeQuery();
因此,我们怀疑这是Oracle JDBC实现的一个BUG,测试运行环境如下:
1. Oracle 10201_database_win32.zip 服务器版本
2. JDBC为10201_database_win32安装中Oracle10.2.0/Server/jdbc/lib/目录下的class12.jar和ojdbc14.jar两个版本都测试过
测试代码:
public static void main(String[] aArgvs)
{
try{
String jdbcUrl = "jdbc:oracle:thin:@localhost:1521:orcl";
Properties pros = new Properties();
pros.setProperty("user", "test");
pros.setProperty("password", "test");
Connection conn = new oracle.jdbc.driver.OracleDriver().connect(jdbcUrl, pros);
PreparedStatement volStat = conn.prepareStatement("SELECT m,n FROM m");
PreparedStatement roleStat = conn.prepareStatement("SELECT m_c,m_f FROM mn WHERE n_c = ? AND n_f = ?");
ResultSet volRs = volStat.executeQuery();
volRs.setFetchSize(100);
while(volRs.next())
{
long con = 1492; // VoltageLevel
long frag = volRs.getLong(1);
String uri = volRs.getString(2);
System.out.print("[" + con + "," + frag + "] " + uri + " : ");
roleStat.setLong(1, con);
roleStat.setLong(2, frag);
// roleStat.setFetchSize(20); // 调用Statement的setFetchSize()方法不会引发问题
ResultSet equipRs = roleStat.executeQuery();
if(equipRs.getFetchSize() < 20) // 调用ResultSet的setFetchSize()方法会引发问题
equipRs.setFetchSize(20);
while(equipRs.next())
{
System.out.print("[" + equipRs.getLong(1) + "," + equipRs.getLong(2) + "]");
}
equipRs.close();
System.out.println("");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}