JDBC在ResultSet中重新读取数据

时间:2012-02-07 12:35:28

标签: java sql-server jdbc resultset

我正在使用Microsoft JDBC驱动程序(mssqlserver.jar)从我的SQL Server数据库中检索一个简单的ResultSet。我认为是从[Microsoft JDBC] [1]

下载的MSSQL2000驱动程序

我想多次调用getter方法来访问值,但是当你执行以下操作时抛出异常:

  

java.sql.SQLException:[Microsoft] [SQLServer 2000 Driver for JDBC] ResultSet无法重新读取第1列的行数据。

问题是,我正在将数据检索到ResultSet中。在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将数据重新打包到自定义类中。

在这个问题上找不到太多帖子。微软网站根本没有任何帮助。

3 个答案:

答案 0 :(得分:2)

根据"ResultSet Can Not Re-Read Row Data"' Error When Reading Data from a JDBC ResultSet Object

,这似乎是设计的
  

包含BLOB列的ResultSet对象(例如,text,ntext或image数据类型)发生此错误。驱动程序无法按顺序返回BLOB列,因为它不会因为大小限制而缓存BLOB数据类型的所有内容。

     

对于ResultSet中的任何行,您可以从左到右读取任何列,并且每列只应读取一次。如果您尝试不按顺序读取列,或者从ResultSet重新读取列,您可能会收到“症状”部分描述的错误消息。

     

此行为是设计

您需要使用不同的JDBC驱动程序,或者重构代码以仅为任何给定行读取一次BLOB列。无论如何,这是个好主意,因为重读BLOB可能会成为性能杀手。

答案 1 :(得分:1)

我建议一次读取数据并复制到Object数组并将其传递给方法而不是传递结果集。这也可以是更干净的代码。

答案 2 :(得分: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()和其他set cursor方法执行相同的操作。所以课程看起来像:

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

}