Pergunta

Recentemente, migrei um aplicativo Java 1.4 para um ambiente Java 6. Infelizmente, encontrei um problema com o BigDecimal armazenamento em um banco de dados Oracle. Para resumir, quando tento armazenar um "7.65E+7" Valor bigdecimal (76,500,000.00) no banco de dados, o Oracle armazena na realidade o valor de 7,650,000.00. Este defeito é devido à reescrição do BigDecimal aula em Java 1.5 (ver aqui).

No meu código, o BigDecimal foi criado de um double Usando esse tipo de código:

BigDecimal myBD = new BigDecimal("" + someDoubleValue);
someObject.setAmount(myBD);
// Now let Hibernate persists my object in DB...

Em mais de 99% dos casos, tudo funciona bem. Exceto que, em poucos casos, ocorre o bug mencionado acima. E isso é bastante irritante.

Se eu alterar o código anterior para evitar o uso do construtor de string de BigDecimal, então eu não encontro o bug Nos meus casos de uso:

BigDecimal myBD = new BigDecimal(someDoubleValue);
someObject.setAmount(myBD);
// Now let Hibernate persists my object in DB...

No entanto, como posso ter certeza de que esta solução é a maneira correta de lidar com o uso de BigDecimal?

Então, minha pergunta é saber como eu tenho para gerenciar meu BigDecimal valores para evitar esse problema:

  • Não use o new BigDecimal(String) construtor e use diretamente o new BigDecimal(double)?
  • Forçar o Oracle a usar toPlainString() ao invés de toString() método ao lidar com BigDecimal (e neste caso como fazer isso)?
  • Alguma outra solução?

Informações do ambiente:

  • Java 1.6.0_14
  • Hibernate 2.1.8 (sim, é uma versão bastante antiga)
  • Oracle JDBC 9.0.2.0 e também testado com 10.2.0.3.0
  • Oracle Database 10.2.0.3.0

Editar: Eu testei o mesmo código em erro, mas com o Oracle JDBC versão 10.2.0.4.0 e o bug fez não ocorrer! O valor armazenado foi de fato 76,500,000.00... Sobre a Changelog, talvez esteja relacionado ao bug #4711863.

Foi útil?

Solução

Com as versões modernas do Hibernate, você pode usar o userType para mapear qualquer classe para um campo de banco de dados. Basta fazer um userType personalizado e usá -lo para mapear o objeto BigDecimal para a coluna do banco de dados.

Ver http://i-proving.com/space/technologies/hibernate/user+Types+in+hibernate

Outras dicas

Confissão: Eu pessoalmente não uso o Hibernate, mas você poderia simplesmente criar um MyBigDecimal subclasse cujo método tostring () chama topLainstring ()?

Também não tenho muita certeza dos méritos de passar um dobro para o cosntrocutor de BigDecimal - um duplo é inerentemente impreciso, a menos que o número seja composto inteiramente de adições de poderes de 2 (com restrições de alcance). O ponto principal do BigDecimal é contornar essas restrições em dobro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top