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免费学习笔记(深入)”;

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。