根據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();
}
}