Avoid the problem with BigDecimal when migrating to Java 1.4 to Java 1.5+

拟墨画扇 提交于 2019-12-23 18:45:54

问题


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 the new BigDecimal(double)?
  • Force Oracle to use toPlainString() instead of toString() method when dealing with BigDecimal (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.


回答1:


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




回答2:


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.



来源:https://stackoverflow.com/questions/2622948/avoid-the-problem-with-bigdecimal-when-migrating-to-java-1-4-to-java-1-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!