nested exception is java.sql.SQLException: 数字溢出的问题解决

时间:2021-10-21 22:53:35

错误现象

今天调试一段代码,里面有个逻辑,要批量取数据;当运行取到第二批数据的时候,程序报了如下错误:

org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [select * from (select t.*,rownum rnm from (select distinct vc.id,
vc.member_id,
vc.order_id,
vc.attribute,
vc.un_service_day,
vc.benefit_customer_id,
vc.gmt_target_end,
vc.biz_status,
vc.ultimate_price,
vc.payment_amount,
vc.num
from ord_order_item vc
where biz_status in ('service', 'issue_ready')
and gmt_target_end < trunc(sysdate, 'dd')
and is_deleted = 'n'
and vc.parent_id + 0 = 0 ) t where rownum<=18000 ) where rnm>9000]; SQL state [null]; error code [17026]; 数字溢出; nested exception is java.sql.SQLException: 数字溢出

第一批是rownum<=9000,rnm>0是能正常运行 的。


解决方案

找到出错的代码进行debug,一层层跟进去后,发现在上面的sql执行后,会把数据做一个如下的操作:

List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList());
int rowNum = 0;
while (rs.next()) {
results.add(this.rowMapper.mapRow(rs, rowNum++));
}
这个rowMapper.mapRow的操作是:

Map<String,Object> resultMap = new HashMap<String, Object>();
resultMap.put("id", rs.getInt("ID"));
resultMap.put("orderId", rs.getInt("ORDER_ID"));
resultMap.put("attribute", rs.getString("ATTRIBUTE"));
resultMap.put("memberId", rs.getString("MEMBER_ID"));
resultMap.put("unServiceDay", rs.getBigDecimal("UN_SERVICE_DAY"));
resultMap.put("benefitCustomerId", rs.getInt("BENEFIT_CUSTOMER_ID"));
resultMap.put("gmtTargetEnd", rs.getDate("GMT_TARGET_END")!=null?DateUtils.truncate(rs.getDate("GMT_TARGET_END"),Calendar.DAY_OF_MONTH):null);
resultMap.put("bizStatus", rs.getString("BIZ_STATUS"));
resultMap.put("ultimatePrice", rs.getBigDecimal("ULTIMATE_PRICE"));
这个映射如果不成功,就会抛java.sql.SQLException异常。仔细想了想数字溢出,会不会是上面的类有数据转成对应数据类型的时候报出来的?

int类型的数据范围是:-2147483648...2147483647。数据库里面再查了下转化类里面的int的字段最大值,果然发现有条记录的ID为31342135233,大大超过了整型的数据范围,所以程序执行到rs.getInt("ID")时就出错了。

把出错ID修改后,程序执行就正常了!


问题反思

1,.看来数字溢出这种出错,有数字对应的类型溢出的意思,不过出错信息还是少了点,而且抛的异常也没有达成对应的出错类,对应调用方查找出错原因花了一些时间。虽然是javaSql自带的出错信息,但如果能稍微封装下也明确不少阿。


2.数据库使用的是oracle,id定义的类型为number,没有定义精度,位数。一般定义Number的方法:Number(p,s),其中p,s都是可选的:

a、p代表精度,默认为38

b、s代表小数位数,取值范围-84~127,默认取值要看是否指定了p,如果制定了p,默认s为0,如果没有指定p,默认取最大值。

而目前的数据库中默认,那么就是Number(38,0),所以随着数据表中数据的增长,这会是个潜在的安全隐患。

3.再复习下数据库字段定义的相关知识:

 1> NUMBER(p,s):固定精度数字类型

2> NUMBER:不固定精度数字类型,当不确定数字的精度时使用,PK通常使用此类型

3> DATE:当仅需要精确到秒时,选择DATE而不是TIMESTAMP类型

     VARCHAR2:变长字符串,最长4000个字节

4> CLOB:当超过4000字节时使用,但是要求这个字段必须单独创建到一张表中,然后有PK与主表关联。此类型应该尽量控制使用