Ruhezustand - Zuordnung von Datum und Uhrzeit

1. Einleitung

In diesem Artikel wird gezeigt, wie temporäre Spaltenwerte in Hibernate zugeordnet werden, einschließlich der Klassen aus den Paketen java.sql , java.util und java.time .

2. Projekteinrichtung

Um die Zuordnung der zeitlichen Typen zu demonstrieren, benötigen wir die H2-Datenbank und die neueste Version der Hibernate-Core- Bibliothek:

 org.hibernate hibernate-core 5.4.12.Final   com.h2database h2 1.4.194 

Die aktuelle Version der Hibernate-Core- Bibliothek finden Sie im Maven Central-Repository.

3. Zeitzoneneinrichtung

Beim Umgang mit Datumsangaben empfiehlt es sich, eine bestimmte Zeitzone für den JDBC-Treiber festzulegen. Auf diese Weise wäre unsere Anwendung unabhängig von der aktuellen Zeitzone des Systems.

In unserem Beispiel richten wir es pro Sitzung ein:

session = HibernateUtil.getSessionFactory().withOptions() .jdbcTimeZone(TimeZone.getTimeZone("UTC")) .openSession();

Eine andere Möglichkeit besteht darin, die Eigenschaft hibernate.jdbc.time_zone in der Eigenschaftendatei Hibernate einzurichten, die zum Erstellen der Sitzungsfactory verwendet wird. Auf diese Weise können wir die Zeitzone einmal für die gesamte Anwendung angeben.

4. Zuordnen von java.sql- Typen

Das Paket java.sql enthält JDBC-Typen, die an den im SQL-Standard definierten Typen ausgerichtet sind:

  • Datum entspricht dem SQL-Typ DATE , bei dem es sich nur um ein Datum ohne Uhrzeit handelt
  • Die Zeit entspricht dem SQL-Typ TIME , bei dem es sich um eine in Stunden, Minuten und Sekunden angegebene Tageszeit handelt
  • Der Zeitstempel enthält Informationen zu Datum und Uhrzeit mit einer Genauigkeit von bis zu Nanosekunden und entspricht dem SQL-Typ TIMESTAMP

Da diese Typen mit SQL übereinstimmen, ist ihre Zuordnung relativ einfach. Wir können entweder die Annotation @Basic oder @Column verwenden :

@Entity public class TemporalValues { @Basic private java.sql.Date sqlDate; @Basic private java.sql.Time sqlTime; @Basic private java.sql.Timestamp sqlTimestamp; }

Wir könnten dann die entsprechenden Werte wie folgt einstellen:

temporalValues.setSqlDate(java.sql.Date.valueOf("2017-11-15")); temporalValues.setSqlTime(java.sql.Time.valueOf("15:30:14")); temporalValues.setSqlTimestamp( java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

Beachten Sie, dass die Auswahl von java.sql- Typen für Entitätsfelder möglicherweise nicht immer eine gute Wahl ist. Diese Klassen sind JDBC-spezifisch und enthalten viele veraltete Funktionen.

5. Mapping java.util.Date Type

Der Typ java.util.Date enthält sowohl Datums- als auch Zeitinformationen mit einer Genauigkeit von bis zu Millisekunden. Es bezieht sich jedoch nicht direkt auf einen SQL-Typ.

Aus diesem Grund benötigen wir eine weitere Anmerkung, um den gewünschten SQL-Typ anzugeben:

@Basic @Temporal(TemporalType.DATE) private java.util.Date utilDate; @Basic @Temporal(TemporalType.TIME) private java.util.Date utilTime; @Basic @Temporal(TemporalType.TIMESTAMP) private java.util.Date utilTimestamp;

Die Annotation @Temporal hat den einzelnen Parameterwert vom Typ TemporalType. Dies kann entweder DATE , TIME oder TIMESTAMP sein , abhängig vom zugrunde liegenden SQL-Typ, den wir für die Zuordnung verwenden möchten.

Wir könnten dann die entsprechenden Felder wie folgt einstellen:

temporalValues.setUtilDate( new SimpleDateFormat("yyyy-MM-dd").parse("2017-11-15")); temporalValues.setUtilTime( new SimpleDateFormat("HH:mm:ss").parse("15:30:14")); temporalValues.setUtilTimestamp( new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") .parse("2017-11-15 15:30:14.332"));

Wie wir gesehen haben, ist der Typ java.util.Date (Millisekundengenauigkeit) nicht präzise genug, um den Zeitstempelwert (Nanosekundengenauigkeit) zu verarbeiten.

Wenn wir also die Entität aus der Datenbank abrufen, finden wir in diesem Feld nicht überraschend eine java.sql.Timestamp- Instanz, selbst wenn wir anfangs eine java.util.Date beibehalten haben :

temporalValues = session.get(TemporalValues.class, temporalValues.getId()); assertThat(temporalValues.getUtilTimestamp()) .isEqualTo(java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

Dies sollte für unseren Code in Ordnung sein , da Zeitstempel erweitert Datum .

6. Zuordnung von java.util.Calendar Type

Wie bei java.util.Date kann der Typ java.util.Calendar verschiedenen SQL-Typen zugeordnet werden, daher müssen wir sie mit @Temporal angeben .

Der einzige Unterschied besteht darin, dass der Ruhezustand die Zuordnung von Kalender zu ZEIT nicht unterstützt :

@Basic @Temporal(TemporalType.DATE) private java.util.Calendar calendarDate; @Basic @Temporal(TemporalType.TIMESTAMP) private java.util.Calendar calendarTimestamp;

So können wir den Wert des Feldes einstellen:

Calendar calendarDate = Calendar.getInstance( TimeZone.getTimeZone("UTC")); calendarDate.set(Calendar.YEAR, 2017); calendarDate.set(Calendar.MONTH, 10); calendarDate.set(Calendar.DAY_OF_MONTH, 15); temporalValues.setCalendarDate(calendarDate);

7. Zuordnen von java.time- Typen

Seit Java 8 steht die neue Java-API für Datum und Uhrzeit für den Umgang mit zeitlichen Werten zur Verfügung . Diese API behebt viele Probleme der Klassen java.util.Date und java.util.Calendar .

Die Typen aus dem Paket java.time werden direkt den entsprechenden SQL-Typen zugeordnet. Es ist also nicht erforderlich, die @ Temporal- Annotation explizit anzugeben :

  • LocalDate ist DATE zugeordnet
  • LocalTime und OffsetTime sind TIME zugeordnet
  • Instant , LocalDateTime , OffsetDateTime und ZonedDateTime werden TIMESTAMP zugeordnet

Dies bedeutet, dass wir diese Felder nur mit der Annotation @Basic (oder @Column ) wie folgt markieren können :

@Basic private java.time.LocalDate localDate; @Basic private java.time.LocalTime localTime; @Basic private java.time.OffsetTime offsetTime; @Basic private java.time.Instant instant; @Basic private java.time.LocalDateTime localDateTime; @Basic private java.time.OffsetDateTime offsetDateTime; @Basic private java.time.ZonedDateTime zonedDateTime;

Jede temporäre Klasse im Paket java.time verfügt über eine statische parse () -Methode, um den angegebenen String- Wert im entsprechenden Format zu analysieren . So können wir die Werte der Entitätsfelder festlegen:

temporalValues.setLocalDate(LocalDate.parse("2017-11-15")); temporalValues.setLocalTime(LocalTime.parse("15:30:18")); temporalValues.setOffsetTime(OffsetTime.parse("08:22:12+01:00")); temporalValues.setInstant(Instant.parse("2017-11-15T08:22:12Z")); temporalValues.setLocalDateTime( LocalDateTime.parse("2017-11-15T08:22:12")); temporalValues.setOffsetDateTime( OffsetDateTime.parse("2017-11-15T08:22:12+01:00")); temporalValues.setZonedDateTime( ZonedDateTime.parse("2017-11-15T08:22:12+01:00[Europe/Paris]"));

8. Fazit

In diesem Artikel haben wir gezeigt, wie zeitliche Werte verschiedener Typen im Ruhezustand zugeordnet werden.

Der Quellcode für den Artikel ist auf GitHub verfügbar.