Spring JDBCによるOracle 10 gデータベース操作時のRowSetの問題


詳細
Spring JDBCを使用してOracle 10 gのデータベースをページングしたときに例外が発生しました.エラーメッセージは次のとおりです.
 
[ERROR]2971656-2009-05-1815:38:24-
[com.ieslab.idp.datamaint.service.impl.DataGridServiceImpl.
buildGrid(DataGridServiceImpl.java:
171)]-[]-org.springframework.jdbc.UncategorizedSQLException: StatementCallback;
uncategorized SQLException for SQL [select * from (select temp.* ,ROWNUM num from ( 
select * from idp_pub_m.  _VW) temp where ROWNUM <= 4 ) where num > 0]; 
SQL state [null]; error code [0]; Invalid scale size. Cannot be less than zero; 
nested exception is java.sql.SQLException: Invalid scale size. Cannot be less than zero 
 
上記のエラーでは、1つのビューからデータを問合せ、個別に実行する場合にページング操作を行います.
select temp.* ,ROWNUM num from 
( select * from idp_pub_m.  _VW) temp where ROWNUM <= 4
 
の場合、エラーはなく、正常に実行できます.あるネットユーザーは、Oracle 10 gで返される結果セットのデータ精度の定義が9 iと異なると話しています.例えば同じように
 
select count(*) from ......

 
文は、oracle 10 gでSpring JDBCを使用すると問題が発生し、例外情報もjavaである.sql.SQLException: Invalid scale size. Cannot be less than zero;SQL文を
 
select count(*)+0  from ......

 
解決できます.
 
これはもう一人のネットユーザーaggie 2000が与えた答えで、ここに貼って、メモとして残しています.ほほほ!
元帖の住所はhttp://forum.springsource.org/showthread.php?t=19848
 
I have been dealing with the same problem (SQLException - "Invalid scale size. Cannot be less than zero") and believe I have arrived at a better solution for those who wish to use the Spring API as much as possible. The basic problem, as I understand it, is that there is an incompatibility between Oracle and the standard CachedRowSet implementation (CachedRowSetImpl) of Java 1.5. Spring uses this implementation by default when you call queryForRowSet(...). However, this does not mean that you cannot use SqlRowSet. The SqlRowSet class doesn't know anything about the implementation of the CachedRowSet interface that you're using. The class that is actually utilizing the CachedRowSetImpl class is the ResultSetExtractor... more specifically, the SqlRowSetResultSetExtractor (this is used by Spring when you call queryForRowSet). In order to achieve the same result (returning a Spring SqlRowSet), you can pass in your own ResultSetExtractor to the query(...) methods (*not* queryForRowSet) that take a ResultSetExtractor as a parameter. What I did was just clone the SqlRowSetResultSetExtractor and instead of using the standard CachedRowSetImpl class, I replaced it with Oracle's CachedRowSet implementation. This way, when the ResultSet is mapped to a CachedRowSet, it uses Oracle's implementation to do so and thus the incompatibility is eliminated. Here is my ResultSetExtractor class that does just that... -------------------------
package com.yada.yada.yada;

import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.rowset.CachedRowSet;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.support.rowset.ResultSetW rappingSqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import oracle.jdbc.rowset.OracleCachedRowSet;

public class SqlRowSetOracleResultSetExtractor implements ResultSetExtractor {

public Object extractData(ResultSet rs) throws SQLException {
return createSqlRowSet(rs);
}

/**
* Create a SqlRowSet that wraps the given ResultSet,
* representing its data in a disconnected fashion.
* 

This implementation creates a Spring ResultSetWrappingSqlRowSet * instance that wraps a standard JDBC CachedRowSet instance. * Can be overridden to use a different implementation. * @param rs the original ResultSet (connected) * @return the disconnected SqlRowSet * @throws SQLException if thrown by JDBC methods * @see #newCachedRowSet * @see org.springframework.jdbc.support.rowset.ResultSetW rappingSqlRowSet */ protected SqlRowSet createSqlRowSet(ResultSet rs) throws SQLException { CachedRowSet rowSet = newCachedRowSet(); rowSet.populate(rs); return new ResultSetWrappingSqlRowSet(rowSet); } /** * Create a new CachedRowSet instance, to be populated by * the createSqlRowSet implementation. *

This implementation creates a new instance of * Oracle's oracle.jdbc.rowset.OracleCachedRowSet class, * which is their implementation of the Java 1.5 CachedRowSet interface. * @return a new CachedRowSet instance * @throws SQLException if thrown by JDBC methods * @see #createSqlRowSet * @see oracle.jdbc.rowset.OracleCachedRowSet */ protected CachedRowSet newCachedRowSet() throws SQLException { return new OracleCachedRowSet(); } }

 
------------------------- You can pass this to the various query methods like so:
SqlRowSet sqlRowSet = (SqlRowSet)jdbcTemplate.query(sql,
 new SqlRowSetOracleResultSetExtractor());

Hope that helps! Seems to be working for me.
 
この問題はaggie 2000からの返信に従って解決しました.上記のコードで参照されているいくつかのクラスはOracle 10 gの駆動ojdbc 14にあります.jarで.具体的な原因については、aggie 2000はすでに答えを出しており、この問題に詳しい友达を歓迎し、討論に返事します.