webentwicklung-frage-antwort-db.com.de

java.util.Date vs Java.sql.Date

Java.util.Date vs Java.sql.Date: Wann und warum welche verwenden?

484
flybywire

Herzlichen Glückwunsch, Sie haben mit JDBC: Date class handling meinen Lieblingstitel erreicht.

Grundsätzlich unterstützen Datenbanken normalerweise mindestens drei Formen von Datums-/Uhrzeitfeldern, nämlich Datum, Uhrzeit und Zeitstempel. Jedes von diesen hat eine entsprechende Klasse in JDBC und jedes von ihnen erweitert Java.util.Date. Die kurze Semantik von jedem dieser drei ist die folgende:

  • Java.sql.Date entspricht SQL DATE, dh es werden Jahre, Monate und Tage gespeichert, während Stunde, Minute und Sekunde und Millisekunde werden ignoriert. Außerdem ist _sql.Date_ nicht an Zeitzonen gebunden.
  • Java.sql.Time entspricht SQL TIME und enthält offensichtlich nur Informationen zu Stunden, Minuten, Sekunden und Millisekunden .
  • Java.sql.Timestamp entspricht SQL TIMESTAMP, was dem genauen Datum der Nanosekunde entspricht ( Beachten Sie, dass _util.Date_ nur Millisekunden unterstützt! ) mit anpassbaren Werten Präzision.

Einer der häufigsten Fehler bei der Verwendung von JDBC-Treibern in Bezug auf diese drei Typen ist, dass die Typen falsch behandelt werden. Dies bedeutet, dass _sql.Date_ ist zeitzonenspezifisch, _sql.Time_ enthält das aktuelle Jahr, den aktuellen Monat und den aktuellen Tag und so weiter.

Endlich: Welches verwenden?

Hängt wirklich vom SQL-Typ des Feldes ab. PreparedStatement hat Setter für alle drei Werte, #setDate() ist derjenige für _sql.Date_, #setTime() für _sql.Time_ und #setTimestamp() für _sql.Timestamp_ .

Beachten Sie, dass Sie bei Verwendung von ps.setObject(fieldIndex, utilDateObject); den meisten JDBC-Treibern tatsächlich einen normalen _util.Date_ zuweisen können, der sie gerne verschlingt, als wäre er vom richtigen Typ, aber wenn Sie die Daten anschließend anfordern, stellen Sie möglicherweise fest, dass dies der Fall ist dass du tatsächlich Sachen vermisst.

Ich sage wirklich, dass keines der Daten überhaupt verwendet werden sollte.

Was ich sage, dass speichern Sie die Millisekunden/Nanosekunden als reine Longs und konvertieren Sie sie in beliebige Objekte, die Sie verwenden (obligatorischer Joda-Time-Plug). Eine Hacky-Methode, die ausgeführt werden kann, besteht darin, die Datumskomponente als eine lange und die Zeitkomponente als eine andere zu speichern. Derzeit sind dies beispielsweise 20100221 und 154536123. Diese magischen Zahlen können in SQL-Abfragen verwendet werden und sind von einer Datenbank in eine andere und übertragbar Mit dieser Option können Sie diesen Teil der JDBC/Java-Datums-API vollständig vermeiden.

569
Esko

LATE EDIT: Ab Java 8 sollten Sie weder _Java.util.Date_ noch _Java.sql.Date_ verwenden, wenn Sie dazu in der Lage sind alle vermeiden es und verwenden stattdessen lieber das Java.time -Paket (basierend auf Joda) als irgendetwas anderes. Wenn Sie nicht mit Java 8 arbeiten, finden Sie hier die ursprüngliche Antwort:


Java.sql.Date - wenn Sie Methoden/Konstruktoren von Bibliotheken aufrufen, die sie verwenden (wie JDBC). Nicht anders. Sie möchten den Datenbankbibliotheken keine Abhängigkeiten für Anwendungen/Module hinzufügen, die sich nicht explizit mit JDBC befassen.

Java.util.Date - bei Verwendung von Bibliotheken, die es verwenden. Ansonsten so wenig wie möglich aus mehreren Gründen:

  • Es ist veränderlich, was bedeutet, dass Sie jedes Mal, wenn Sie es an eine Methode übergeben oder von einer Methode zurückgeben, eine defensive Kopie davon erstellen müssen.

  • Es geht nicht sehr gut mit Datumsangaben um, was Leute wie Ihre wirklich tun sollten.

  • Nun, da j.u.D seine Arbeit nicht sehr gut macht, wurden die schrecklichen Klassen Calendar eingeführt. Sie sind auch veränderlich und es ist schrecklich, mit ihnen zu arbeiten. Sie sollten vermieden werden, wenn Sie keine andere Wahl haben.

  • Es gibt bessere Alternativen, wie die Joda Time API (das könnte es sogar in Java 7 schaffen und die neue offizielle API für die Datumsverarbeitung werden - a Schnellsuche sagt, dass dies nicht der Fall ist).

Wenn Sie der Meinung sind, dass es übertrieben ist, eine neue Abhängigkeit wie Joda einzuführen, sind longs nicht allzu schlecht für Zeitstempelfelder in Objekten, obwohl ich sie normalerweise selbst in juD einhülle, wenn ich sie weitergebe, aus Gründen der Sicherheit und als Dokumentation.

58
gustafc

Java.sql.Date kann nur in einem PreparedStatement.setDate verwendet werden. Verwenden Sie andernfalls Java.util.Date. Es heißt, dass ResultSet.getDate einen Java.sql.Date zurückgibt, dieser kann jedoch direkt einem Java.util.Date zugewiesen werden.

19
Paul Tomblin

Ich hatte das gleiche Problem. Der einfachste Weg, das aktuelle Datum in eine vorbereitete Anweisung einzufügen, ist der folgende:

preparedStatement.setDate(1, new Java.sql.Date(new Java.util.Date().getTime()));
10
Israelm

Die Java.util.Date-Klasse in Java stellt einen bestimmten Zeitpunkt dar (z. B. 25.11.2013, 16:30:45 bis auf Millisekunden), der Datentyp DATE in der DB jedoch nur ein Datum (zB 25.11.2013). Um zu verhindern, dass Sie versehentlich ein Java.util.Date-Objekt für die Datenbank bereitstellen, können Sie mit Java keinen SQL-Parameter direkt auf Java.util.Date setzen:

PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, d); //will not work

Sie können dies aber trotzdem mit Gewalt/Absicht tun (dann werden Stunden und Minuten vom DB-Treiber ignoriert). Dies geschieht mit der Java.sql.Date-Klasse:

PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, new Java.sql.Date(d.getTime())); //will work

Ein Java.sql.Date-Objekt kann einen Moment in der Zeit speichern (so dass es einfach aus einem Java.util.Date zu konstruieren ist), löst jedoch eine Ausnahme aus, wenn Sie versuchen, es nach Stunden zu fragen (um sein Konzept des Seins eines zu erzwingen) nur Datum). Es wird erwartet, dass der DB-Treiber diese Klasse erkennt und nur 0 für die Stunden verwendet. Versuche dies:

public static void main(String[] args) {
  Java.util.Date d1 = new Java.util.Date(12345);//ms since 1970 Jan 1 midnight
  Java.sql.Date d2 = new Java.sql.Date(12345);
  System.out.println(d1.getHours());
  System.out.println(d2.getHours());
}
2
Kent Tong