日期:2014-05-16  浏览次数:20501 次

Spring JDBC对Oracle10g数据库操作时RowSet的问题

使用Spring JDBC对Oracle10g进行数据库分页的时候出现了异常,错误信息如下:

?

[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 
?

上面错误中,进行的操作是从一个视图中查询数据并进行分页操作,当单独执行:

select temp.* ,ROWNUM num from 
( select * from idp_pub_m.厂站_VW) temp where ROWNUM <= 4
?

时,是没有错误的,可以成功执行。有网友说是Oracle10g中对返回的结果集中数据精度的定义和9i中不同;例如同样是

?

select count(*) from ......

?

语句,在oracle 10g中使用Spring JDBC操作时就会有问题,异常信息同样是 java.sql.SQLException: Invalid scale size. Cannot be less than zero;将SQL语句写为

?

select count(*)+0  from ......

?

就可以解决。

?

这是另一个网友aggie2000 给出的解答,贴于此处,留作备忘。呵呵!

原帖地址是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.
* <p>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.spr