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

评论(0)