在使用Spring中的NamedParameterJdbcTemplate.queryForRowSet()方法时,抛出了SQLException:Invalid scale size. Cannot be less than zero的异常。
google之后知道出现这种错误有两种情况:
1是当所查询的列类型为number,而且没有指定具体的精度时。处理这个问题相对来说比较简单,更改列类型增加精度就可以了;
2是当数据库环境为oracle而且使用了RowSet时。具体原因是由于“oracle驱动面对一个数值型的返回字段时,在得到指定的字段小数点右边的数值数量时(Gets the designated column's number of digits to right of the decimal point.这个是原文),居然会返回-127,而oracle本身的cacheRowSet实现不允许这种情况出现,于是就会报标题所说的异常。”(原文出自
马面萨满的灵魂小屋)
针对问题2的解决办法就要复杂的多,需要对ResultSetMetaData中getScale()方法的原有的返回结果加以处理,需要修改的部分如下,其它部分照旧重写即可。
1 public class ResultSetWrapper implements ResultSet {
2 public ResultSetWrapper(ResultSet wrapped) {
3 this.wrapped = wrapped;
4 }
5
6 public ResultSetMetaData getMetaData() throws SQLException {
7 // TODO Auto-generated method stub
8 // return null;
9 return new ResultSetMetadataWrapper(this.wrapped.getMetaData());
10 }
11}
12
13
14 public class ResultSetMetadataWrapper implements ResultSetMetaData {
15
16 public int getScale(int arg0) throws SQLException {
17 // TODO Auto-generated method stub
18 //return 0;
19
20 int result = this.wrapped.getScale(arg0);
21 return result < 0? 0: result;
22 }
23 }
为了在spring中应用我们所实现的ResultSetWrapper和ResultSetMetaDataWrapper,需要重写spring中的SqlRowSetResultSetExtractor和NamedParameterJdbcTemplate,具体代码如下
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.rowset.CachedRowSet;
import org.springframework.jdbc.core.SqlRowSetResultSetExtractor;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSet;
public class CustomSqlRowSetResultSetExtractor
extends
SqlRowSetResultSetExtractor {
protected SqlRowSet createSqlRowSet(ResultSet rs) throws SQLException {
CachedRowSet rowSet = newCachedRowSet();
rowSet.populate(new ResultSetWrapper(rs));
return new ResultSetWrappingSqlRowSet(rowSet);
}
}
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.rowset.SqlRowSet;
public class CustomNamedParameterJdbcTemplate extends NamedParameterJdbcTemplate {
public CustomNamedParameterJdbcTemplate(DataSource ds) {
super(ds);
}
public SqlRowSet queryForRowSet(String sql, SqlParameterSource paramSource) throws DataAccessException {
return (RowSet) getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), new CustomSqlRowSetResultSetExtractor());
}
public SqlRowSet queryForRowSet(String sql, Map paramMap) throws DataAccessException {
return queryForRowSet(sql, new MapSqlParameterSource(paramMap));
}
}
在需要使用NamedParameterJdbcTemplate的地方使用我们自定义的CustomNamedParameterJdbcTemplate即可。需要说明的是我是在使用spring版本2.0.*、2.5.5时出现的该错误。或许它更应该和RowSet、oracle驱动的版本有关;)