将数字(22,21)映射到BigDecimal时,Hibernate在结果中的精度损失

时间:2011-04-20 17:08:41

标签: java oracle hibernate double bigdecimal

我在Oracle 11g中将此列映射为NUMBER(21,20),它在Hibernate中映射为:

@Column(name = "PESO", precision = 21, scale = 20, nullable = false)
public BigDecimal getWeight() {
    return weight;
}

对于列的值为0.493的特定记录,我得到一个BigDecimal,其值为0.49299999999。 似乎某个地方由于(可能)Double或Float转换而导致精度损失,但我无法通过这样的简单单元测试来跟踪它:

Double d = new Double("0.493");
System.out.println((d));

该代码的任何变体,使用Float,BigDecimal和各种构造函数都会得到相同的结果:“0.493”...... 有关如何映射列以避免此类问题的任何提示? 我正在使用Hibernate 3.5.6,带有JPA注释和Hibernate API(即Session而不是EntityManager)

2 个答案:

答案 0 :(得分:3)

这是从BigDecimal初始化double的结果:

System.out.println(String.format("%21.20f", new BigDecimal(0.493)); 
// Prints 0,49299999999999999378  

因此,当BigDecimal初始化时,这种方式被保存在数据库中,它会产生一个不准确的值,以后会正确加载。

如果BigDecimal是由字符串初始化的,或者如果直接在Java中设置了值,那么一切正常。

答案 1 :(得分:0)

对我来说,获胜的解决方案是基于 How do I map a BigDecimal in Hibernate so I get back the same scale I put in? 的解决方案:

private final int SCALE = 2;
private final RoundingMode ROUNDING_MODE = RoundingMode.CEILING;

@Column(name = "value", precision = 8, scale = 2)
private BigDecimal value;

public BigDecimal getValue() {
    return value.setScale(SCALE, ROUNDING_MODE);
}

所以,我只是提供了一个执行大十进制自动整理的 getter。