我正在使用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将数据重新打包到自定义类中。
在这个问题上找不到太多帖子。微软网站根本没有任何帮助。
答案 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
}