Saltar al contenido

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

Hola, encontramos la solución a tu interrogante, continúa leyendo y la obtendrás más abajo.

Solución:

La información completa (y es más compleja de lo que se describe aquí y podría depender de la versión particular de los controladores de Oracle que se estén utilizando) se encuentra en la respuesta de Richard Yee aquí: [now expired link to Nabble]


Agarre rápido antes de que expire 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 DATE SQL a java.sql.Timestamp. Esto tenía cierto sentido porque el tipo SQL DATE de Oracle contiene información de fecha y hora, al igual que java.sql.Timestamp. La asignación más obvia a java.sql.Date fue algo problemática 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 SQL TIMESTAMP, por lo que no hubo ningún problema con la asignación de DATE a Timestamp.

En 9.2, se agregó soporte 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 la información de la hora, existe un problema.

Hay varias formas de abordar este problema:

Modifique sus tablas para usar TIMESTAMP en lugar de DATE. Probablemente esto sea posible en raras ocasiones, 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 (consulte ¿Qué es defineColumnType y cuándo debería 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 el mapeo antiguo en lugar del nuevo. Puede establecer este indicador como una propiedad de conexión o una propiedad del sistema. La propiedad de conexión se establece agregándola al objeto java.util.Properties pasado a DriverManager.getConnection o a OracleDataSource.setConnectionProperties. La propiedad del sistema se establece al incluir una opción -D en la línea de comandos de Java.

java -Doracle.jdbc.V8Compatible = “true”MyApp Oracle 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á en desuso. No debe usar en absoluto. Si lo configura en true no hará daño a nada, pero debes dejar de usarlo.

Aunque rara vez se usaba de esa manera, V8Compatible existía no para solucionar el problema DATE to Date sino para admitir la compatibilidad con bases de datos 8i. Las bases de datos 8i (y anteriores) no admitían el tipo TIMESTAMP. La configuración de V8Compatible no solo hizo que SQL DATE se asignara a Timestamp cuando se leyera desde la base de datos, sino que también causó que todas las Timestamps se convirtieran a SQL DATE cuando se escribieran 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 de forma predeterminada convierten SQL DATE en Timestamp al leer 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 puede notar una diferencia es si confió en la conversión de FECHA a Fecha para truncar el componente de tiempo o si lo hace aString 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. Establecer mapDateToTimestamp en false y el controlador volverá al comportamiento predeterminado de 9i-10g y mapeará la FECHA a la Fecha.

Si es posible, debe cambiar el 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 conoce 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 Oracle sql DATE 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 DATE que está siendo devuelta por este fragmento de SQL:

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

La llamada al procedimiento de 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 contra una tabla.

En PL / SQL Developer, una de las columnas devueltas, FROM_DATE, de tipo SQL DATE, tiene precisión con respecto a la 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 al 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 la época Martes 16 de diciembre de 2008 11:59:00 p.m. PST

Pero obteniendo esto en su lugar: 1229414400000 milisegundos desde época Martes 16 de diciembre de 2008 12:00:00 AM PST (como instancia de la clase java.sql.Date)

No importa lo que intente, no puedo exponer la precisión total de esta columna DATE 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 probé:

o

Pero todas las asignaciones intentadas producen 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 siquiera lo 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 código SQL como un script de prueba. Nada aceptable, muy frustrante y, en última instancia, muy aterrador.

Descubrí cómo solucionar este problema. iBATIS permite el registro de manejadores de tipos personalizados. Entonces, en mi archivo sqlmap-config.xml agregué esto:



Y luego agregó esta clase que implementa la interfaz iBATIS TypeHandlerCallback:

// corrected getResult()/setParameter() to correctly deal with when value is null
public class CustomDateHandler implements TypeHandlerCallback 
    @Override
    public Object getResult(ResultGetter getter) throws SQLException 
        final Object obj = getter.getTimestamp();
        return obj != null ? (Date) obj : null;
    

    @Override
    public void setParameter(ParameterSetter setter,Object value) throws SQLException 
        setter.setTimestamp(value != null ? new Timestamp(((Date)value).getTime()) : null);
    

    @Override
    public Object valueOf(String datetime) 
        return Timestamp.valueOf(datetime);
    

Cuando siempre necesito mapear una FECHA de Oracle, ahora lo describo así:


He resuelto mi problema usando jdbcType="TIMESTAMP" en lugar de jdbcType="DATE"

• PROBLEMA:


• RESUELTO:


Te mostramos las comentarios y valoraciones de los lectores

Recuerda que puedes dar visibilidad a esta crónica si te fue de ayuda.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *