Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Problema de conversão Oracle SQL DATE usando iBATIS via Java JDBC


As informações completas (e são mais complexas do que as descritas aqui e podem depender de qual versão específica dos drivers Oracle estão em uso) está na resposta de Richard Yee aqui - [link agora expirado para Nabble]

Agarre rápido antes que expire do nabble...

Roger,Veja:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01

Especificamente:Tipos de dados simples O que está acontecendo com DATE e TIMESTAMP? Esta seção é sobre tipos de dados simples. :-)

Antes da versão 9.2, os drivers Oracle JDBC mapeavam o tipo DATE SQL para java.sql.Timestamp. Isso fez certo sentido porque o tipo Oracle DATE SQL contém informações de data e hora, assim como java.sql.Timestamp. O mapeamento mais óbvio para java.sql.Date foi um pouco problemático, pois java.sql.Date não inclui informações de tempo. Também acontecia que o RDBMS não suportava o tipo SQL TIMESTAMP, portanto, não havia problema em mapear DATE para Timestamp.

Na versão 9.2, o suporte TIMESTAMP foi adicionado ao RDBMS. A diferença entre DATE e TIMESTAMP é que TIMESTAMP inclui nanossegundos e DATE não. Assim, a partir do 9.2, DATE é mapeado para Date e TIMESTAMP é mapeado para Timestamp. Infelizmente, se você estivesse contando com valores DATE para conter informações de tempo, há um problema.

Existem várias maneiras de resolver esse problema:

Altere suas tabelas para usar TIMESTAMP em vez de DATE. Isso provavelmente raramente é possível, mas é a melhor solução quando é.

Altere seu aplicativo para usar defineColumnType para definir as colunas como TIMESTAMP em vez de DATE. Há problemas com isso porque você realmente não deseja usar defineColumnType a menos que seja necessário (consulte O que é defineColumnType e quando devo usá-lo?).

Altere seu aplicativo para usar getTimestamp em vez de getObject. Esta é uma boa solução quando possível, porém muitos aplicativos contêm código genérico que depende de getObject, então nem sempre é possível.

Configure a propriedade de conexão V8Compatible. Isso diz aos drivers JDBC para usar o mapeamento antigo em vez do novo. Você pode definir esse sinalizador como uma propriedade de conexão ou uma propriedade do sistema. Você configura a propriedade de conexão incluindo-a no objeto java.util.Properties passado para DriverManager.getConnection ou OracleDataSource.setConnectionProperties. Você define a propriedade do sistema incluindo uma opção -D em sua linha de comando java.

java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 corrige esse problema. A partir desta versão, o driver mapeia as colunas SQL DATE para java.sql.Timestamp por padrão. Não há necessidade de definir V8Compatible para obter o mapeamento correto. V8Compatible está fortemente obsoleto. Você não deve usá-lo em tudo. Se você definir como verdadeiro, não vai doer nada, mas você deve parar de usá-lo.

Embora raramente fosse usado dessa maneira, o V8Compatible existia não para corrigir o problema DATE to Date, mas para oferecer suporte à compatibilidade com bancos de dados 8i. Os bancos de dados 8i (e mais antigos) não suportavam o tipo TIMESTAMP. Definir V8Compatible não apenas fez com que SQL DATE fosse mapeado para Timestamp quando lido do banco de dados, mas também fez com que todos os Timestamps fossem convertidos em SQL DATE quando gravados no banco de dados. Como o 8i não é compatível, os drivers JDBC 11.1 não suportam esse modo de compatibilidade. Por esse motivo, o V8Compatible não é compatível.

Como mencionado acima, os drivers 11.1 por padrão convertem SQL DATE em Timestamp ao ler do banco de dados. Isso sempre foi a coisa certa a fazer e a mudança no 9i foi um erro. Os drivers 11.1 reverteram para o comportamento correto. Mesmo que você não tenha definido V8Compatible em seu aplicativo, não deverá ver nenhuma diferença de comportamento na maioria dos casos. Você pode notar uma diferença se usar getObject para ler uma coluna DATE. O resultado será um carimbo de data/hora em vez de uma data. Como Timestamp é uma subclasse de Date, isso geralmente não é um problema. Onde você pode notar uma diferença é se você confiou na conversão de DATE para Date para truncar o componente de tempo ou se você fizer toString no valor. Caso contrário, a mudança deve ser transparente.

Se por algum motivo seu aplicativo for muito sensível a essa mudança e você simplesmente precisar ter o comportamento 9i-10g, existe uma propriedade de conexão que você pode definir. Defina mapDateToTimestamp como false e o driver reverterá para o comportamento padrão 9i-10g e mapeará DATE para Date.

Se possível, você deve alterar o tipo de coluna para TIMESTAMP em vez de DATE.

-Richard

Roger Voss escreveu:Eu postei a seguinte pergunta/problema no stackoverflow, então se alguém souber uma resolução, seria bom vê-la respondida lá:

Problema de conversão Oracle SQL DATE usando iBATIS via Java JDBC

Segue a descrição do problema:

Atualmente estou lutando com um problema de conversão Oracle sql DATE usando iBATIS de Java.

Estou usando o driver thin Oracle JDBC ojdbc14 versão 10.2.0.4.0. iBATIS versão 2.3.2. Java 1.6.0_10-rc2-b32.

O problema gira em torno de uma coluna do tipo DATE que está sendo retornada por este trecho de SQL:

SELECT *FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) ordenar por from_date

A chamada de procedimento de pacote retorna um cursor ref que está sendo encapsulado em uma TABELA para onde é fácil ler o conjunto de resultados como se fosse uma consulta de seleção em uma tabela.

No PL/SQL Developer, uma das colunas retornadas, FROM_DATE, do tipo SQL DATE, tem precisão de hora do dia:
Tue Dec 16 23:59:00 PST 2008

Mas quando acesso isso via iBATIS e JDBC, o valor só mantém a precisão até o dia:
Tue Dec 16 12:00:00 AM PST 2008

Isso fica mais claro quando exibido assim:

Deveria ter sido:1229500740000 milissegundos desde epochTerça-feira, 16 de dezembro de 2008 23:59:00 PST

Mas obtendo isso:1229414400000 milissegundos desde epochTerça-feira, 16 de dezembro de 2008 12:00:00 AM PST (como instância da classe java.sql.Date)

Não importa o que eu tente, não consigo expor a precisão total desta coluna DATE para ser retornada via Java JDBC e iBATIS.

O que o iBATIS está mapeando é o seguinte:

FROM_DATE :2008-12-03 :class java.sql.Date

O mapeamento atual do iBATIS é este:



Eu também tentei:



ou



Mas todas as tentativas de mapeamento geram o mesmo valor de Data truncado. É como se o JDBC já tivesse causado o dano de perder a precisão dos dados antes mesmo de o iBATIS tocar nele.

Claramente estou perdendo parte da minha precisão de dados passando por JDBC e iBATIS que não está acontecendo quando permaneço no PL/SQL Developer executando o mesmo trecho de SQL como um script de teste. Nada aceitável, muito frustrante e, em última análise, muito assustador.