4.1 Udflugt til historien

Opgaven med at gemme Java-objekter til databasen var relevant næsten umiddelbart efter oprettelsen af ​​Java-sproget. På det tidspunkt var der kun én datatype i Java-sproget, Date, som lagrede tid i henhold til UNIX-tidsstandarden: som antallet af millisekunder siden 1970.

Nå, i databaserne på det tidspunkt var der allerede forskellige datatyper for datoer, i det mindste var der separate typer for dato, tid og dato + tid:

  • DATO
  • TID
  • TIDSSTEMPEL

Derfor tilføjede skaberne af Java-sproget en speciel pakke til det - java.sql, som indeholdt klasser:

  • java.sql.date
  • java.sql.Time
  • java.sql.tidsstempel

At kortlægge disse klasser er en sand fornøjelse:


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

Men da programmører plejede at arbejde med klassen java.util.Date, tilføjede Hibernate en speciel annotering @Temporalfor at kontrollere tilknytningen af ​​datotypen.

Eksempel:

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

Typen java.util.Calendarog java.util.Datestandardtypen bruger TIMESTAMP- typen til at repræsentere dem i databasen.

4.2 Ny tid

På nuværende tidspunkt, med kortlægning, er alt meget enklere og bedre. Alle databaser understøtter 4 typer data til at arbejde med tiden:

  • DATO - dato: år, måned og dag.
  • TID - tid: timer, minutter, sekunder.
  • TIMESTAMP - dato, tid og nanosekunder.
  • TIDSSTYKKE MED TIDZONE - TIDSSTYKKE og tidszone (zonenavn eller offset).

At repræsentere typen DATOi Java skal du bruge en klasse java.time.LocalDatefra JDK 8 DateTime API.

TypeTIDfra databasen kan repræsenteres af to typer fra Java: java.time.LocalTimeog java.time.OffsetTime. Intet kompliceret.

Og den nøjagtige dato og klokkeslæt repræsenteret af typenTIDSSTEMPELi basen kan det i Java repræsenteres af 4 typer:

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

Og endeligTIDSSTIMPEL MED TIDZONEkan repræsenteres af to typer:

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

Da du allerede er bekendt med DateTime API , vil det ikke være svært for dig at huske denne sag :)

At kortlægge dem er ren fornøjelse:

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

Annoteringen @Basicbetyder, at feltet skal behandles automatisk : Hibernate vil bestemme, hvilken kolonne og type dette felt skal tilknyttes.

4.3 Arbejde med tidszoner

Hvis tidszonen er en del af en dato, så er det nemt at gemme dem i databasen - ligesom en almindelig dato:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Men hvis du vil gemme tidszoner adskilt fra datoen:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Så vil Hibernate gemme dem i VARCHAR-typen som standard. Hvilket faktisk er logisk, da TimeZone normalt har et strengnavn som "UTC + 3" eller "Cairo".

4.4 Indstilling af din egen tidszone

Når du arbejder med at gemme datoer til databasen, vil du støde på, at der allerede er 4 steder, hvor du kan indstille den aktuelle tidszone:

  • Server operativsystem;
  • DBMS;
  • Java-applikation
  • Gå i dvale.

Hvis DBMS'en ikke angiver en tidszone (TimeZone), vil den tage den fra operativsystemets indstillinger. Dette kan være ubelejligt, da backup-DBMS'er ofte er placeret i andre datacentre, der har deres egen tidszone.

Derfor indstiller næsten alle DBMS-administratorer en enkelt zone, så data nemt kan overføres fra en server til en anden.

Situationen er den samme med en Java-applikation. Det kan også køres på forskellige servere i forskellige datacentre, så det har normalt en eksplicit tidszone.


java -Duser.timezone=UTC ...

Eller mens programmet kører:

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

Og selvfølgelig giver Hibernate dig mulighed for at indstille din tidszone eksplicit.

For det første kan det specificeres, når du konfigurerer SessionFactory:

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

For det andet kan tidszonen angivestil en bestemt session:

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

4.5 @TimeZoneStorage annotation

Det sker ofte, at programmører begyndte at designe en database baseret på at arbejde i ét land (og én tidszone), og efter et par år skulle de tilføje support til at arbejde i forskellige tidszoner.

Derfor tilføjede de blot en separat kolonne til databasen for at gemme tidszonen. Dette er så almindelig en situation, at Hibernate har tilføjet en speciel anmærkning, der giver dig mulighed for at gemme tidszonen for en bestemt dato i en separat kolonne.

Eksempel:

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

Dette er en krykke. Men der er også en undskyldning for det: det dukkede op på et tidspunkt, hvor DateTime API'en endnu ikke eksisterede. Og det var umuligt at gemme TimeZone i klassen java.util.Date.

Jeg håber virkelig, at du ikke ofte vil se dette i din kode.