【问题标题】:Hibernate loss of precision in results when mapping a number (22,21) to BigDecimal将数字 (22,21) 映射到 BigDecimal 时,结果中的 Hibernate 精度损失
【发布时间】:2011-08-09 16:39:51
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 看来这不是休眠故障...这完全在 SquirrelSql 上,它显示 0.493 的值为 0.49299999999...该值一直是那个,在“源”文件中,都在数据库中,正如 SqlDeveloper 报告的那样。

标签: java oracle hibernate double bigdecimal


【解决方案1】:

对我来说,获胜的解决方案是基于 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。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 感谢这个例子,可能 "%21.20" 部分有一些技巧,因为 System.out.println(String.format("%f", new BigDecimal(0.493)));打印几乎没问题->“0,493000”。但这不是我的情况:-)
    猜你喜欢
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 2016-09-22
    • 2016-12-19
    • 2020-07-08
    相关资源
    最近更新 更多