2012-02-07 41 views
2

我正在使用Microsoft JDBC驅動程序(mssqlserver.jar)從我的SQL Server數據庫檢索一個簡單的ResultSet。我認爲這是從[微軟JDBC]下載MSSQL2000驅動程序[1]JDBC在結果集中重新讀取數據

我想調用getter方法不止一次訪問值,但是當你做下面的異常被拋出:

java.sql.SQLException:[微軟] [SQLServer 2000的爲JDBC驅動程序] ResultSet不能重新讀取行數據作爲第1列

的問題是,我檢索數據到一個結果。從ResultSet中,我在將ResultSet傳遞到代碼中的其他地方以便重用之前訪問我的代碼中的數據。

代碼類似於如下:

// build query string 
String selectQuery = "SELECT * FROM SomeWhere"; 

// get the data 
Statement statement = sourceConnection.createStatement(); 
ResultSet rs = statement.executeQuery(selectQuery); 

while(rs.next()) { 

    // do my own internal processing 
    doSomethingWithRs(rs); 

    // now do something with the record set outside - in subclass 
    afterRowCopied(rs); 
} 

// ... 

private void doSomethingWithRs(ResultSet rs) { 
    // access data 
    for(int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { 
     Object o = rs.getObject(i); 
     // do something with o... 
    } 

} 

編輯

我使用Java 1.6的這一點。

末編輯

有什麼想法? 我所能想到的就是用ResultSetMetaData重新打包數據到自定義類中。

在這個問題上沒有發現太多帖子。微軟網站根本沒有任何幫助。

+1

是否有可能。你可以使用jtds代替http://jtds.sourceforge.net/ – 2012-02-07 12:49:29

+0

sandeepnair85,這個東西可以展望未來 - 當然。但由於所有事情都是以數據庫爲導向的,所以不能改變,因爲管理層不會100%置信地替換,這會導致很多測試。將爲你的答案+1,但你必須已經刪除,然後再對 – Andez 2012-02-07 14:15:51

回答

1

我建議讀取一次數據並複製到Object數組並將其傳遞給方法而不是傳遞結果集。這也可以是更乾淨的代碼。

+0

prajeesh發表評論,我需要結果集的元數據,在那裏我操縱它超級類的outisde,所以Object數組不足以滿足這個例子。 – Andez 2012-02-07 14:14:46

+0

那麼,如果你需要元數據,你也可以傳遞結果集,但不能一次又一次地讀取結果集。創建一個'List ',將值讀入一次,並用這個附加參數調用方法。我不知道它會適合多少,但這至少可以讓事情以最小的開銷進行。 – 2012-02-07 16:36:11

2

這似乎是由設計,根據"ResultSet Can Not Re-Read Row Data"' Error When Reading Data from a JDBC ResultSet Object:與包含BLOB列(例如,文本,ntext或圖像數據類型)ResultSet對象發生

此錯誤。驅動程序不能無序地返回BLOB列,因爲它不會因大小限制而緩存BLOB數據類型的所有內容。

對於ResultSet中的任何行,您可以從左到右讀取任何列,並且每個列只能讀取一次。如果您嘗試不按順序讀取列,或者如果重新讀取ResultSet中的列,則可能會收到「症狀」一節所述的錯誤消息。

此行爲爲設計

您要麼需要使用不同的JDBC驅動程序,要麼重構您的代碼,以便只讀取任何給定行的BLOB列一次。無論如何,這是一個好主意,因爲重讀BLOB可能會成爲一個性能殺手。

+0

skaffman,這正是我所看到的 - 讀取行後next()被稱爲。可能會矯枉過正,但是會創建一個新的類來實現ResultSet,並看看我得到了多少。有100多種方法可以覆蓋! – Andez 2012-02-07 12:59:41

1

漫長的噩夢般的方法(雖然有效),但我懶洋洋地實施了大部分獲得者。

編輯

正如我所說,我使用JDK 1.6。然而,當對JDK 1.7編譯時遇到編譯錯誤:

error: ReadOnlyResultSet is not abstract and does not override abstract method <T>getObject(String,Class<T>) in ResultSet 

末編輯

爲此創建一個實現的ResultSet類(讓Netbeans中添加默認的方法實現存根)。然後在構造函數中存儲對初始ResultSet的引用。在next()中,緩存數組中的值。對於previous()和其他設置的遊標方法,可能必須做同樣的事情。因此,類將是這樣的:你更改驅動程序

public class ReadOnlyResultSet 
    implements ResultSet { 
    /** 
    * The original data source. 
    */ 
    private ResultSet source; 
    /** 
    * Cached values for the current row. 
    */ 
    private Object[] values; 

    /** 
    * Creates a new instance of <code>ReadOnlyResultSet</code>. 
    */ 
    public ReadOnlyResultSet(ResultSet source) { 
     this.source = source; 
    } 

    @Override 
    public boolean next() throws SQLException { 
     // NOTE: values[0] will always be null as JDBC is 1 based arrays 
     boolean next = source.next(); 
     if(next) { 
      values = new Object[source.getMetaData().getColumnCount() + 1]; 
       for(int i = 1; i < source.getMetaData().getColumnCount(); i++) { 
        values[i] = source.getObject(i); 
       } 
      } else { 
       // no current row 
       values = new Object[] { }; 
      } 

      return next; 
     } 

     // implement all of the not getter/setter methods 
     @Override 
     public void close() throws SQLException { 
      source.close(); 
     } 

     // implement getters I am interested in 
     @Override 
     public String getString(int columnIndex) throws SQLException { 
      return (String) values[columnIndex]; 
     } 

     @Override 
     public String getString(String columnLabel) throws SQLException { 
      return (String) values[findColumn(columnLabel)]; 
     } 

     // just too much implementation but hopefully you get the drift 

}