Ruhezustand - Zuordnung von Datum und Uhrzeit

Ruhezustand - Zuordnen von Datum und Uhrzeit

1. Einführung

In diesem Artikel wird gezeigt, wie zeitliche Spaltenwerte im Ruhezustand zugeordnet werden, einschließlich der Klassen aus den Paketenjava.sql,java.util undjava.time.

2. Projektaufbau

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


    org.hibernate
    hibernate-core
    5.2.12.Final


    com.h2database
    h2
    1.4.194

Die aktuelle Version der Bibliothekhibernate-corefinden Sie im RepositoryMaven Central.

3. Zeitzoneneinstellung

When dealing with dates, it’s a good idea to set a specific time zone for the JDBC driver. 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 Eigenschafthibernate.jdbc.time_zonein der Eigenschaftendatei für den Ruhezustand einzurichten, die zum Erstellen der Sitzungsfactory verwendet wird. Auf diese Weise können wir die Zeitzone für die gesamte Anwendung einmal angeben.

4. Zuordnung vonjava.sql-Typen

Das Paketjava.sqlenthält JDBC-Typen, die an den im SQL-Standard definierten Typen ausgerichtet sind:

  • Date entspricht dem SQL-TypDATE, bei dem es sich nur um ein Datum ohne Uhrzeit handelt

  • Time entspricht dem SQL-TypTIME, bei dem es sich um eine in Stunden, Minuten und Sekunden angegebene Tageszeit handelt

  • Timestamp enthält Informationen zu Datum und Uhrzeit mit einer Genauigkeit von bis zu Nanosekunden und entspricht dem SQL-TypTIMESTAMP

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 vonjava.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. Mappingjava.util.Date Typ

The type java.util.Date contains both date and time information, up to millisecond precision. 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 Einzelparameterwert vom TypTemporalType.. Sie kann entwederDATE,TIME oderTIMESTAMP sein, abhängig vom gewünschten zugrunde liegenden SQL-Typ für das Mapping zu verwenden.

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

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,the java.util.Date type (milliseconds precision) is not precise enough to handle the Timestamp value (nanoseconds precision).

Wenn wir also die Entität aus der Datenbank abrufen, finden wir in diesem Feld nicht überraschend einejava.sql.Timestamp-Instanz, selbst wenn wir anfänglich einejava.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, daTimestampDate erweitert.

6. Mappingjava.util.Calendar Typ

Wie beijava.util.Date kann der Typjava.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 vonCalendar zuTIME 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 festlegen:

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. Zuordnung vonjava.time-Typen

Since Java 8, the new Java Date and Time API is available for dealing with temporal values. Diese API behebt viele Probleme der Klassenjava.util.Date undjava.util.Calendar.

Die Typen aus dem Paketjava.timewerden direkt den entsprechenden SQL-Typen zugeordnet. Es ist also nicht erforderlich, die Annotation von@Temporalexplizit anzugeben:

  • LocalDate wirdDATE zugeordnet

  • LocalTime undOffsetTime werdenTIME zugeordnet

  • Instant,LocalDateTime,OffsetDateTime undZonedDateTime werdenTIMESTAMP 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 zeitliche Klasse im Paketjava.timehat eine statische Methodeparse(), um den bereitgestellten WertStringunter Verwendung des entsprechenden Formats 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 wird gezeigt, wie Sie Zeitwerte verschiedener Typen in Hibernate zuordnen.

Der Quellcode für den Artikel istover on GitHub verfügbar.