从 Java 1.4 迁移到 Java 1.5 时避免 BigDecimal 的问题+
我最近将 Java 1.4 应用程序迁移到 Java 6 环境。不幸的是,我在 Oracle 数据库中的 BigDecimal
存储方面遇到了问题。总而言之,当我尝试在数据库中存储 "7.65E+7"
BigDecimal 值 (76,500,000.00
) 时,Oracle 实际上存储的值是 7,650,000.00< /代码>。该缺陷是由于 Java 1.5 中对
BigDecimal
类的重写造成的(参见 此处)。
在我的代码中,BigDecimal
是使用这种代码从 double
创建的:
BigDecimal myBD = new BigDecimal("" + someDoubleValue);
someObject.setAmount(myBD);
// Now let Hibernate persists my object in DB...
在超过 99% 的情况下,一切正常。除了极少数情况下,会发生上述错误。这很烦人。
如果我更改前面的代码以避免使用 BigDecimal
的 String 构造函数,那么我在我的用例中不会遇到错误:
BigDecimal myBD = new BigDecimal(someDoubleValue);
someObject.setAmount(myBD);
// Now let Hibernate persists my object in DB...
但是,我如何确定该解决方案是处理 BigDecimal 使用的正确方法吗?
所以我的问题是知道如何管理我的 BigDecimal 值以避免此问题:
- 不要使用 new BigDecimal(String) 构造函数并直接使用新的 BigDecimal(double) ?
- 在处理 BigDecimal 时强制 Oracle 使用 toPlainString() 而不是 toString() 方法(在这种情况下该怎么做)?
- 还有其他解决方案吗?
环境信息:
- Java 1.6.0_14
- Hibernate 2.1.8(是的,这是一个相当旧的版本)
- Oracle JDBC 9.0.2.0 并使用 10.2.0.3.0 进行了测试
- Oracle 数据库 10.2.0.3.0
编辑: 我已经测试了错误的相同代码,但使用 Oracle JDBC 版本 10.2.0.4.0 并且错误没有出现!存储的值确实是76,500,000.00
... 关于changelog,也许是相关的错误#4711863。
I've recently migrated a Java 1.4 application to a Java 6 environment. Unfortunately, I encountered a problem with the BigDecimal
storage in a Oracle database. To summarize, when I try to store a "7.65E+7"
BigDecimal value (76,500,000.00
) in the database, Oracle stores in reality the value of 7,650,000.00
. This defect is due to the rewritting of the BigDecimal
class in Java 1.5 (see here).
In my code, the BigDecimal
was created from a double
using this kind of code:
BigDecimal myBD = new BigDecimal("" + someDoubleValue);
someObject.setAmount(myBD);
// Now let Hibernate persists my object in DB...
In more than 99% of the cases, everything works fine. Except that in really few case, the bug mentioned above occurs. And that's quite annoying.
If I change the previous code to avoid the use of the String constructor of BigDecimal
, then I do not encounter the bug in my uses cases:
BigDecimal myBD = new BigDecimal(someDoubleValue);
someObject.setAmount(myBD);
// Now let Hibernate persists my object in DB...
However, how can I be sure that this solution is the correct way to handle the use of BigDecimal
?
So my question is to know how I have to manage my BigDecimal
values to avoid this issue:
- Do not use the
new BigDecimal(String)
constructor and use directly thenew BigDecimal(double)
? - Force Oracle to use
toPlainString()
instead oftoString()
method when dealing withBigDecimal
(and in this case how to do that)? - Any other solution?
Environment information:
- Java 1.6.0_14
- Hibernate 2.1.8 (yes, it is a quite old version)
- Oracle JDBC 9.0.2.0 and also tested with 10.2.0.3.0
- Oracle database 10.2.0.3.0
Edit : I've tested the same code in error but with the Oracle JDBC version 10.2.0.4.0 and the bug did not occur! The value stored was indeed 76,500,000.00
...
Regarding the changelog, maybe it is related to the bug #4711863.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用现代 Hibernate 版本,您可以使用 UserType 将任何类映射到数据库字段。只需创建一个自定义 UserType 并使用它将 BigDecimal 对象映射到数据库列。
请参阅http://i-proving.com/space/Technologies /Hibernate/User+Types+in+Hibernate
With modern Hibernate versions you can use UserType to map any class to a database field. Just make a custom UserType and use it to map BigDecimal object to database column.
See http://i-proving.com/space/Technologies/Hibernate/User+Types+in+Hibernate
坦白:我个人不使用 Hibernate,但是您可以创建一个子类 MyBigDecimal,其 toString() 方法调用 toPlainString() 吗?
我也不完全确定将双精度数传递给 BigDecimal 的构造函数的优点——双精度数本质上是不准确的,除非该数字完全由 2 的幂相加组成(有范围限制)。 BigDecimal 的全部目的是规避这些对 double 的限制。
Confession: I don't personally use Hibernate, but could you just create a subclass MyBigDecimal whose toString() method calls toPlainString()?
I'm also not entirely sure of the merits of passing a double into the cosntructor of BigDecimal -- a double is inherently inaccurate unless the number is composed entirely of additions of powers of 2 (with range restrictions). The whole point of BigDecimal is to circumvent these restrictions on double.