应使用 getbigdecimal() 获取 oracle 的 number 类型数据,因其能精确表示十进制数值;而 getdouble() 因 double 是二进制浮点数,会导致精度丢失,尤其在小数、大数或金融场景中明显。
java 读 oracle 的浮点数(比如 number 列)时用 double 拿,精度大概率已经丢了——不是 java 的锅,是 double 本身不能精确表示大多数十进制小数。
为什么 ResultSet.getDouble() 会丢精度
Oracle 的 NUMBER 类型是十进制高精度类型,而 double 是二进制浮点(IEEE 754),两者语义不匹配。例如 Oracle 存了 0.1,Double 实际存的是近似值 0.10000000000000000555...;再比如 9999999999999999.99 这种大数加小数,double 根本存不下末尾两位。
- 常见错误现象:
getDouble()返回值和数据库里查出来的原始值对不上,尤其在金额、科学计算、审计场景下肉眼可见偏差 - Oracle JDBC 驱动默认把
NUMBER映射成BigDecimal(只要没显式调用getDouble),但很多人直接写rs.getDouble("amount")就绕过了这个保护 - 不是所有
NUMBER都有问题:整数且在±2^53范围内,double还能扛住;但只要带小数位、或超长整数,就危险
怎么安全地从 ResultSet 拿 Oracle 数字
直接用 getBigDecimal(),这是最稳的路径。JDBC 规范要求 Oracle 驱动必须支持它,且返回值与数据库存储完全一致。
- 别写
rs.getDouble("price"),改写成rs.getBigDecimal("price") - 如果字段可能为
NULL,记得判空:BigDecimal price = rs.getBigDecimal("price"); if (price != null) { ... } - 不要用
new BigDecimal(double)去“转换”——这只会把已丢失的精度再封装一遍,错上加错 - 如果业务层确实需要
double(比如喂给某个只认double的旧库),务必用bigDecimal.doubleValue(),并清楚这是有损操作,仅限展示或非关键路径
BigDecimal 运算时容易踩的坑
拿到 BigDecimal 只是第一步,后续计算如果不小心,照样引入误差。
- 构造函数别用
double参数:new BigDecimal(0.1)→ 实际是0.10000000000000000555...;该用字符串:new BigDecimal("0.1") - 除法必须指定
scale和RoundingMode,否则抛ArithmeticException:val1.divide(val2, 2, RoundingMode.HALF_UP) - 比较用
compareTo(),别用equals():new BigDecimal("1.0").equals(new BigDecimal("1"))返回false(因 scale 不同) - 数据库里定义的是
NUMBER(10,2)?那业务里做加减也应统一保留 2 位小数,避免中间结果多出无效精度干扰后续逻辑
真正麻烦的不是“怎么换 BigDecimal”,而是那些散落在各处的隐式 double 转换、日志打印时的自动 toString() 截断、前端传参时又转回字符串再解析……精度问题从来不是单点故障,而是一条链路上的松动环节。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










