Die vollständigen Informationen (und sie sind komplexer als hier beschrieben und können davon abhängen, welche bestimmte Version der Oracle-Treiber verwendet wird) finden Sie in Richard Yees Antwort hier - [jetzt abgelaufener Link zu Nabble]
Schnell greifen, bevor es von Nabble abläuft ...
Roger, siehe:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01
Insbesondere:Einfache DatentypenWas passiert mit DATE und TIMESTAMP?Dieser Abschnitt befasst sich mit einfachen Datentypen. :-)
Vor 9.2 haben die Oracle JDBC-Treiber den DATE-SQL-Typ java.sql.Timestamp zugeordnet. Dies machte einen gewissen Sinn, da der Oracle-SQL-Typ DATE sowohl Datums- als auch Zeitinformationen enthält, ebenso wie java.sql.Timestamp. Die offensichtlichere Zuordnung zu java.sql.Date war etwas problematisch, da java.sql.Date keine Zeitinformationen enthält. Es war auch so, dass das RDBMS den TIMESTAMP-SQL-Typ nicht unterstützte, daher gab es kein Problem mit der Zuordnung von DATE zu Timestamp.
In 9.2 wurde die TIMESTAMP-Unterstützung zum RDBMS hinzugefügt. Der Unterschied zwischen DATE und TIMESTAMP besteht darin, dass TIMESTAMP Nanosekunden enthält und DATE nicht. Ab 9.2 wird also DATE Date und TIMESTAMP Timestamp zugeordnet. Leider gibt es ein Problem, wenn Sie sich auf DATE-Werte verlassen haben, um Zeitinformationen zu enthalten.
Es gibt mehrere Möglichkeiten, dieses Problem zu lösen:
Ändern Sie Ihre Tabellen, um TIMESTAMP anstelle von DATE zu verwenden. Dies ist wahrscheinlich selten möglich, aber wenn es so ist, ist es die beste Lösung.
Ändern Sie Ihre Anwendung so, dass sie defineColumnType verwendet, um die Spalten als TIMESTAMP und nicht als DATE zu definieren. Es gibt Probleme damit, weil Sie defineColumnType wirklich nicht verwenden wollen, es sei denn, Sie müssen es tun (siehe Was ist defineColumnType und wann sollte ich es verwenden?).
Ändern Sie Ihre Anwendung so, dass sie getTimestamp anstelle von getObject verwendet. Dies ist, wenn möglich, eine gute Lösung, jedoch enthalten viele Anwendungen generischen Code, der auf getObject angewiesen ist, daher ist dies nicht immer möglich.
Legen Sie die V8Compatible-Verbindungseigenschaft fest. Dies weist die JDBC-Treiber an, die alte Zuordnung anstelle der neuen zu verwenden. Sie können dieses Flag entweder als Verbindungseigenschaft oder als Systemeigenschaft festlegen. Sie legen die Verbindungseigenschaft fest, indem Sie sie dem java.util.Properties-Objekt hinzufügen, das an DriverManager.getConnection oder an OracleDataSource.setConnectionProperties übergeben wird. Sie legen die Systemeigenschaft fest, indem Sie eine -D-Option in Ihre Java-Befehlszeile einfügen.
java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 behebt dieses Problem. Ab dieser Version ordnet der Treiber SQL-DATE-Spalten standardmäßig java.sql.Timestamp zu. Es ist nicht erforderlich, V8Compatible festzulegen, um die richtige Zuordnung zu erhalten. V8Compatible ist stark veraltet. Sie sollten es auf keinen Fall verwenden. Wenn Sie es auf true setzen, wird es nichts schaden, aber Sie sollten es nicht mehr verwenden.
Obwohl es selten auf diese Weise verwendet wurde, existierte V8Compatible nicht, um das DATE to Date-Problem zu beheben, sondern um die Kompatibilität mit 8i-Datenbanken zu unterstützen. 8i (und ältere) Datenbanken unterstützten den TIMESTAMP-Typ nicht. Das Festlegen von V8Compatible führte nicht nur dazu, dass SQL DATE beim Lesen aus der Datenbank dem Timestamp zugeordnet wurde, sondern auch dazu, dass alle Timestamps beim Schreiben in die Datenbank in SQL DATE konvertiert wurden. Da 8i nicht mehr unterstützt wird, unterstützen die 11.1 JDBC-Treiber diesen Kompatibilitätsmodus nicht. Aus diesem Grund wird V8Compatible nicht mehr unterstützt.
Wie oben erwähnt, konvertieren die 11.1-Treiber beim Lesen aus der Datenbank standardmäßig SQL DATE in Timestamp. Das war immer richtig und der Wechsel in 9i war ein Fehler. Die 11.1-Treiber sind auf das korrekte Verhalten zurückgekehrt. Auch wenn Sie V8Compatible in Ihrer Anwendung nicht eingestellt haben, sollten Sie in den meisten Fällen keinen Unterschied im Verhalten feststellen. Möglicherweise stellen Sie einen Unterschied fest, wenn Sie getObject zum Lesen einer DATE-Spalte verwenden. Das Ergebnis ist eher ein Zeitstempel als ein Datum. Da Timestamp eine Unterklasse von Date ist, ist dies im Allgemeinen kein Problem. Möglicherweise bemerken Sie einen Unterschied, wenn Sie sich auf die Konvertierung von DATE in Date verlassen haben, um die Zeitkomponente zu kürzen, oder wenn Sie toString für den Wert verwenden. Andernfalls sollte die Änderung transparent sein.
Wenn Ihre App aus irgendeinem Grund sehr empfindlich auf diese Änderung reagiert und Sie einfach das 9i-10g-Verhalten benötigen, können Sie eine Verbindungseigenschaft festlegen. Setzen Sie mapDateToTimestamp auf false und der Treiber kehrt zum Standardverhalten von 9i-10g zurück und ordnet DATE to Date zu.
Wenn möglich, sollten Sie Ihren Spaltentyp in TIMESTAMP statt DATE ändern.
-Richard
Roger Voss schrieb:Ich habe folgende Frage/Problem auf Stackoverflow gepostet, also wenn jemand eine Lösung kennt, wäre es gut, sie dort beantwortet zu sehen:
Oracle SQL DATE-Konvertierungsproblem bei Verwendung von iBATIS über Java JDBC
Hier ist die Problembeschreibung:
Ich kämpfe derzeit mit einem Oracle sql DATE-Konvertierungsproblem mit iBATIS von Java.
Ich verwende den Oracle JDBC Thin-Treiber ojdbc14 Version 10.2.0.4.0. iBATIS-Version 2.3.2. Java 1.6.0_10-rc2-b32.
Das Problem dreht sich um eine Spalte vom Typ DATE, die von diesem SQL-Snippet zurückgegeben wird:
SELECT *FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) order by from_date
Der Aufruf der Paketprozedur gibt einen ref-Cursor zurück, der in eine TABLE eingeschlossen wird, wo die Ergebnismenge dann einfach gelesen werden kann, als wäre es eine Auswahlabfrage für eine Tabelle.
In PL/SQL Developer hat eine der zurückgegebenen Spalten, FROM_DATE, vom Typ SQL DATE, die Genauigkeit der Tageszeit:
Tue Dec 16 23:59:00 PST 2008
Aber wenn ich über iBATIS und JDBC darauf zugreife, behält der Wert nur die Tagesgenauigkeit:
Tue Dec 16 12:00:00 AM PST 2008
Dies ist klarer, wenn es so angezeigt wird:
Sollte gewesen sein:1229500740000 Millisekunden seit EpocheDienstag, 16. Dezember 2008 23:59:00 Uhr PST
Aber stattdessen bekomme ich Folgendes:1229414400000 Millisekunden seit epochTuesday, December 16, 2008 00:00:00 AM PST (als Instanz der Klasse java.sql.Date)
Egal was ich versuche, ich bin nicht in der Lage, die volle Genauigkeit dieser DATE-Spalte anzuzeigen, die über Java JDBC und iBATIS zurückgegeben werden soll.
Was iBATIS abbildet, ist Folgendes:
FROM_DATE :2008-12-03 :Klasse java.sql.Date
Die aktuelle iBATIS-Zuordnung lautet wie folgt:
Ich habe auch versucht:
oder
Aber alle versuchten Zuordnungen ergeben denselben abgeschnittenen Datumswert. Es ist, als hätte JDBC bereits den Schaden angerichtet, indem es die Datenpräzision verloren hat, bevor iBATIS sie überhaupt berührt.
Offensichtlich verliere ich etwas von meiner Datenpräzision, wenn ich JDBC und iBATIS durchlaufe, was nicht passiert, wenn ich in PL/SQL Developer bleibe und denselben SQL-Ausschnitt als Testskript ausführe. Überhaupt nicht akzeptabel, sehr frustrierend und letztendlich sehr beängstigend.