【问题标题】:Issue in retrieving a property mapped with a BigInteger in Hibernate在 Hibernate 中检索与 BigInteger 映射的属性时出现问题
【发布时间】:2020-02-19 11:08:12
【问题描述】:

我遇到了关于使用 Hibernate 检索 10^18 位数字的问题。虽然我不完全确定这完全是 Oracle 数据库、Grails、Hibernate 还是 Java 问题。考虑到这个 Grails 域类:

class Payment {
    BigInteger id
    BigDecimal amount

    static mapping = {        
        id generator: "assigned"
        version false
    }
}

我通过检索遇到问题:

Payment savePayment() {
    BigInteger id = 201910151421550246D
    BigDecimal amount = 100.00G

    Payment payment = new Payment()

    payment.id = id
    payment.amount amount

    payment.save(flush: true)

    Payment retrievedPayment = Payment.findById(id)

    println "payment.id: " + payment.id
    println "payment.amount: " + payment.amount
    println "retrievedPayment.id: " + retrievedPayment.id
    println "retrievedPayment.amount: " + retrievedPayment.amount

    // payment.id: 201910151421550246
    // payment.amount: 100.00
    // retrievedPayment.id: 201910151421550240
    // retrievedPayment.amount: 100.00

    return retrievedPayment
}

我在保存之前将201910151421550246 分配为 id,并且如果它在数据库中相同,我还确认了它的值。它是。此外,当我尝试使用该id 检索所述记录时,我仍然可以检索相同的Payment 记录。问题是为什么值偏离了 6 个点?我目前正在将其映射到String 数据类型,并在我需要执行数字运算时将其转换为 BigInteger 作为临时解决方案。

【问题讨论】:

标签: java hibernate grails


【解决方案1】:

这不是 Oracle 数据库或 Java BigInteger 或休眠的问题,因为它们支持超过 201910151421550246 个数。

在 Web 应用程序的上下文中,大于 Number.MAX_SAFE_INTEGER 的值对于浏览器来说是不可靠的。

就像我们打印 console.log(201910151421550246);在 javascript 中,我们得到 201910151421550240 作为输出。

所以,如果你想使用大于 Number.MAX_SAFE_INTEGER 的数字,那么将其转换为 String 后再使用。

【讨论】:

  • "在 web 应用程序的上下文中,大于 Number.MAX_SAFE_INTEGER 的值对于浏览器来说不可靠。" - 作为对问题的回答,这对我来说没有意义。即使这不是网络应用程序,您也会看到完全相同的行为。
  • @JeffScottBrown 我不了解 Grails,但我可以告诉您,当您在 Java Web 服务器上运行或作为 java 独立应用程序运行时,所提出的问题不会产生任何问题。但是当你在浏览器上打印大于 Number.MAX_SAFE_INTEGER 的数字时,它可能会改变。
  • “我不了解 Grails,但我可以告诉您,当您在 Java Web 服务器上运行或作为 Java 独立应用程序运行时,所提出的问题不会产生任何问题。” - 我认为这是不正确的。我们的 GORM 实现和 Hibernate 在 Web 应用程序外部对此的处理方式完全相同。
【解决方案2】:

要点的第一行是线索。您正在使用文字“D”后缀定义 Double,而 Double 不能准确表示您想要的整数。请参阅“Floating-Point Literals”。当转换为 BigInteger 时,会出现舍入错误。使用字符串来创建 BigInteger,或者对于文字使用双重职责 G suffix,它适用于 BigInteger 和 BigDecimal。

groovy:000> i=201910151421550246D
===> 2.0191015142155024E17
groovy:000> i.class
===> class java.lang.Double
groovy:000> j=(BigInteger)i
===> 201910151421550240
groovy:000> j.class
===> class java.math.BigInteger
groovy:000> id = new BigInteger("201910151421550246")
===> 201910151421550246
groovy:000> id.class
===> class java.math.BigInteger
groovy:000> b=201910151421550246G
===> 201910151421550246
groovy:000> b.class
===> class java.math.BigInteger
groovy:000> id==b
===> true
groovy:000> d=100.0G
===> 100.0
groovy:000> d.class
===> class java.math.BigDecimal

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-06
    • 2010-12-04
    • 1970-01-01
    • 2016-03-07
    • 2012-09-25
    • 2011-07-31
    • 2021-10-24
    • 1970-01-01
    相关资源
    最近更新 更多