sql >> Base de Datos >  >> RDS >> Oracle

Problema de conversión de Oracle SQL DATE usando iBATIS a través de Java JDBC

La información completa (y es más compleja que la descrita aquí y puede depender de qué versión particular de los controladores de Oracle se estén usando) está en la respuesta de Richard Yee aquí - [enlace a Nabble ahora caducado]

Toma rápida antes de que caduque de nabble...

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

Específicamente:Tipos de datos simples ¿Qué está pasando con DATE y TIMESTAMP? Esta sección trata sobre tipos de datos simples. :-)

Antes de 9.2, los controladores JDBC de Oracle asignaban el tipo de SQL DATE a java.sql.Timestamp. Esto tenía cierto sentido porque el tipo Oracle DATE SQL contiene información de fecha y hora al igual que java.sql.Timestamp. El mapeo más obvio a java.sql.Date fue algo problemático ya que java.sql.Date no incluye información de tiempo. También se dio el caso de que el RDBMS no admitía el tipo de SQL TIMESTAMP, por lo que no hubo problema con la asignación de DATE a Timestamp.

En 9.2, se agregó compatibilidad con TIMESTAMP al RDBMS. La diferencia entre DATE y TIMESTAMP es que TIMESTAMP incluye nanosegundos y DATE no. Entonces, a partir de 9.2, DATE se asigna a Date y TIMESTAMP se asigna a Timestamp. Desafortunadamente, si confiaba en los valores de FECHA para contener información de tiempo, hay un problema.

Hay varias formas de abordar este problema:

Modifique sus tablas para usar TIMESTAMP en lugar de DATE. Probablemente esto rara vez sea posible, pero es la mejor solución cuando lo es.

Modifique su aplicación para usar defineColumnType para definir las columnas como TIMESTAMP en lugar de DATE. Hay problemas con esto porque realmente no desea usar defineColumnType a menos que tenga que hacerlo (vea ¿Qué es defineColumnType y cuándo debo usarlo?).

Modifique su aplicación para usar getTimestamp en lugar de getObject. Esta es una buena solución cuando es posible, sin embargo, muchas aplicaciones contienen código genérico que se basa en getObject, por lo que no siempre es posible.

Establezca la propiedad de conexión V8Compatible. Esto le dice a los controladores JDBC que usen la asignación anterior en lugar de la nueva. Puede establecer este indicador como una propiedad de conexión o como una propiedad del sistema. Establece la propiedad de conexión agregándola al objeto java.util.Properties pasado a DriverManager.getConnection oa OracleDataSource.setConnectionProperties. Establece la propiedad del sistema al incluir una opción -D en su línea de comandos de Java.

java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 soluciona este problema. A partir de esta versión, el controlador asigna las columnas SQL DATE a java.sql.Timestamp de forma predeterminada. No es necesario configurar V8Compatible para obtener la asignación correcta. V8Compatible está totalmente obsoleto. No deberías usarlo en absoluto. Si lo establece en verdadero, no le hará ningún daño, pero debería dejar de usarlo.

Aunque rara vez se usaba de esa manera, V8Compatible no existía para solucionar el problema de DATE to Date sino para admitir la compatibilidad con las bases de datos 8i. Las bases de datos 8i (y anteriores) no admitían el tipo TIMESTAMP. La configuración de V8Compatible no solo provocó que la FECHA SQL se asignara a la marca de tiempo cuando se leía de la base de datos, sino que también provocó que todas las marcas de tiempo se convirtieran a FECHA SQL cuando se escribieron en la base de datos. Dado que 8i no es compatible, los controladores JDBC 11.1 no admiten este modo de compatibilidad. Por esta razón, V8Compatible no es compatible.

Como se mencionó anteriormente, los controladores 11.1 convierten de forma predeterminada la FECHA SQL a la marca de tiempo cuando se lee de la base de datos. Esto siempre fue lo correcto y el cambio en 9i fue un error. Los controladores 11.1 han vuelto al comportamiento correcto. Incluso si no configuró V8Compatible en su aplicación, no debería ver ninguna diferencia en el comportamiento en la mayoría de los casos. Puede notar una diferencia si usa getObject para leer una columna FECHA. El resultado será una marca de tiempo en lugar de una fecha. Dado que Timestamp es una subclase de Date, esto generalmente no es un problema. Donde podría notar una diferencia es si confió en la conversión de DATE a Date para truncar el componente de tiempo o si lo hace con toString en el valor. De lo contrario, el cambio debería ser transparente.

Si por alguna razón su aplicación es muy sensible a este cambio y simplemente debe tener el comportamiento 9i-10g, hay una propiedad de conexión que puede establecer. Establezca mapDateToTimestamp en falso y el controlador volverá al comportamiento predeterminado de 9i-10g y asignará FECHA a fecha.

Si es posible, debe cambiar su tipo de columna a TIMESTAMP en lugar de DATE.

-Ricardo

Roger Voss escribió:Publiqué la siguiente pregunta/problema en stackoverflow, por lo que si alguien sabe una resolución, sería bueno verla respondida allí:

Problema de conversión de Oracle SQL DATE usando iBATIS a través de Java JDBC

Aquí está la descripción del problema:

Actualmente estoy luchando con un problema de conversión de FECHA de Oracle sql usando iBATIS de Java.

Estoy usando el controlador delgado Oracle JDBC ojdbc14 versión 10.2.0.4.0. iBATIS versión 2.3.2. Java 1.6.0_10-rc2-b32.

El problema gira en torno a una columna de tipo FECHA que devuelve este fragmento de SQL:

SELECCIONE *DE LA TABLA(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) ordenar por from_date

La llamada al procedimiento del paquete devuelve un cursor de referencia que se envuelve en una TABLA donde es fácil leer el conjunto de resultados como si fuera una consulta de selección en una tabla.

En PL/SQL Developer, una de las columnas devueltas, FROM_DATE, de tipo SQL DATE, tiene precisión de hora del día:

Tue Dec 16 23:59:00 PST 2008

Pero cuando accedo a esto a través de iBATIS y JDBC, el valor solo conserva la precisión hasta el día:

Tue Dec 16 12:00:00 AM PST 2008

Esto es más claro cuando se muestra así:

Debería haber sido:1229500740000 milisegundos desde epochMartes, 16 de diciembre de 2008 11:59:00 p. m. PST

Pero obteniendo esto en su lugar:1229414400000 milisegundos desde epochTuesday, 16 de diciembre de 2008 12:00:00 a. m. PST (como instancia de la clase java.sql.Date)

No importa lo que intente, no puedo exponer la precisión completa de esta columna FECHA para que se devuelva a través de Java JDBC e iBATIS.

Lo que iBATIS está mapeando es esto:

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

El mapeo actual de iBATIS es este:

También he probado:

o

Pero todas las asignaciones intentadas arrojan el mismo valor de fecha truncado. Es como si JDBC ya hubiera hecho el daño de perder la precisión de los datos antes de que iBATIS los toque.

Claramente, estoy perdiendo parte de la precisión de mis datos al pasar por JDBC e iBATIS, lo que no sucede cuando permanezco en PL/SQL Developer ejecutando el mismo fragmento de SQL como script de prueba. Nada aceptable, muy frustrante y, en última instancia, muy aterrador.