4.1 Exkurs in die Geschichte

Die Aufgabe, Java-Objekte in der Datenbank zu speichern, war fast unmittelbar nach der Erstellung der Java-Sprache relevant. Damals gab es in der Java-Sprache nur einen Datentyp, Date, der die Zeit gemäß dem UNIX-Zeitstandard speicherte: als Anzahl der Millisekunden seit 1970.

Nun, in den damaligen Datenbanken gab es bereits unterschiedliche Datentypen für Datumsangaben, zumindest gab es getrennte Typen für Datum, Uhrzeit und Datum + Uhrzeit:

  • DATUM
  • ZEIT
  • ZEITSTEMPEL

Daher haben die Ersteller der Java-Sprache ein spezielles Paket hinzugefügt – java.sql, das Klassen enthielt:

  • java.sql.date
  • java.sql.Time
  • java.sql.timestamp

Das Zuordnen dieser Klassen ist ein wahres Vergnügen:


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

Da Programmierer jedoch früher mit der Klasse arbeiteten java.util.Date, fügte Hibernate eine spezielle Annotation hinzu @Temporal, um die Zuordnung des Date-Typs zu steuern.

Beispiel:

// If the annotation is missing, then the database will have a TIMESTAMP type
Date dateAsTimestamp;

@Temporal(TemporalType.DATE) // will be mapped to DATE type
Date dateAsDate;

@Temporal(TemporalType.TIME) // will be mapped to TIME type
Date dateAsTime;

Der Typ java.util.Calendarund java.util.Dateder Standardtyp verwenden den Typ TIMESTAMP , um sie in der Datenbank darzustellen.

4.2 Neue Zeit

Derzeit ist mit Mapping alles viel einfacher und besser. Alle Datenbanken unterstützen vier Datentypen für die Arbeit mit der Zeit:

  • DATUM – Datum: Jahr, Monat und Tag.
  • ZEIT – Zeit: Stunden, Minuten, Sekunden.
  • TIMESTAMP – Datum, Uhrzeit und Nanosekunden.
  • ZEITSTEMPEL MIT ZEITZONE – ZEITSTEMPEL und Zeitzone (Zonenname oder Offset).

Zur Darstellung des Typs DATUMIn Java müssen Sie eine Klasse java.time.LocalDateaus der JDK 8 DateTime API verwenden.

TypZEITaus der Datenbank können durch zwei Typen aus Java dargestellt werden: java.time.LocalTimeund java.time.OffsetTime. Nichts Kompliziertes.

Und das genaue Datum und die genaue Uhrzeit, die durch den Typ dargestellt werdenZEITSTEMPELIn der Basis kann es in Java durch 4 Typen dargestellt werden:

  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Und schlussendlichZEITSTEMPEL MIT ZEITZONEkann durch zwei Typen dargestellt werden:

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Da Sie bereits mit der DateTime-API vertraut sind , wird es Ihnen nicht schwer fallen, sich an diese Angelegenheit zu erinnern :)

Sie zu kartieren ist pure Freude:

@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;

Die Anmerkung @Basicbedeutet, dass das Feld automatisch verarbeitet werden soll : Hibernate entscheidet, welche Spalte und welchen Typ dieses Feld zugeordnet werden soll.

4.3 Arbeiten mit Zeitzonen

Wenn die Zeitzone Teil eines Datums ist, ist das Speichern in der Datenbank einfach – genau wie bei einem normalen Datum:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Wenn Sie jedoch Zeitzonen getrennt vom Datum speichern möchten:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Dann speichert Hibernate sie standardmäßig im Typ VARCHAR. Was tatsächlich logisch ist, da die Zeitzone normalerweise einen Zeichenfolgennamen wie „UTC + 3“ oder „Kairo“ hat.

4.4 Einstellen Ihrer eigenen Zeitzone

Wenn Sie mit der Speicherung von Daten in der Datenbank arbeiten, werden Sie feststellen, dass es bereits vier Stellen gibt, an denen Sie die aktuelle Zeitzone einstellen können:

  • Server-Betriebssystem;
  • DBMS;
  • Java-Anwendung
  • Überwintern.

Wenn das DBMS keine Zeitzone (TimeZone) angibt, übernimmt es diese aus den Betriebssystemeinstellungen. Dies kann unpraktisch sein, da sich Backup-DBMS häufig in anderen Rechenzentren befinden, die über eine eigene Zeitzone verfügen.

Daher richten fast alle DBMS-Administratoren eine einzelne Zone ein, damit Daten problemlos von einem Server auf einen anderen übertragen werden können.

Ähnlich verhält es sich mit einer Java-Anwendung. Es kann auch auf verschiedenen Servern in unterschiedlichen Rechenzentren betrieben werden, daher wird ihm in der Regel explizit eine Zeitzone zugewiesen.


java -Duser.timezone=UTC ...

Oder während das Programm läuft:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

Und natürlich ermöglicht Ihnen Hibernate, Ihre Zeitzone explizit festzulegen.

Zunächst kann bei der Konfiguration der SessionFactory angegeben werden:

settings.put(
    AvailableSettings.JDBC_TIME_ZONE,
    TimeZone.getTimeZone("UTC")
);

Zweitens kann die Zeitzone angegeben werdenfür eine bestimmte Sitzung:

Session session = sessionFactory()
    .withOptions()
    .jdbcTimeZone(TimeZone.getTimeZone("UTC"))
    .openSession();

4.5 @TimeZoneStorage-Annotation

Es kommt oft vor, dass Programmierer mit dem Entwurf einer Datenbank auf der Grundlage der Arbeit in einem Land (und einer Zeitzone) begannen und dann nach ein paar Jahren Unterstützung für die Arbeit in verschiedenen Zeitzonen hinzufügen mussten.

Deshalb haben sie einfach eine separate Spalte zur Datenbank hinzugefügt, um die Zeitzone zu speichern. Dies kommt so häufig vor, dass Hibernate eine spezielle Anmerkung hinzugefügt hat, mit der Sie die Zeitzone eines bestimmten Datums in einer separaten Spalte speichern können.

Beispiel:

@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name = "birthday_offset_offset")
@Column(name = "birthday_offset")
private OffsetDateTime offsetDateTimeColumn;

@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name = "birthday_zoned_offset")
@Column(name = "birthday_zoned")
private ZonedDateTime zonedDateTimeColumn;

Das ist eine Krücke. Dafür gibt es aber auch eine Entschuldigung: Es erschien zu einer Zeit, als die DateTime-API noch nicht existierte. Und es war unmöglich, TimeZone in der Klasse zu speichern java.util.Date.

Ich hoffe wirklich, dass Sie dies nicht oft in Ihrem Code sehen werden.