4.1 Utflukt til historien

Oppgaven med å lagre Java-objekter til databasen var relevant nesten umiddelbart etter opprettelsen av Java-språket. På den tiden var det bare én datatype i Java-språket, Date, som lagret tid i henhold til UNIX-tidsstandarden: som antall millisekunder siden 1970.

Vel, i databasene på den tiden var det allerede forskjellige datatyper for datoer, i det minste var det separate typer for dato, klokkeslett og dato + klokkeslett:

  • DATO
  • TID
  • TIDSSTIMPEL

Derfor la skaperne av Java-språket en spesiell pakke til det - java.sql, som inneholdt klasser:

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

Å kartlegge disse timene er en sann glede:


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

Men siden programmerere pleide å jobbe med klassen java.util.Date, la Hibernate til en spesiell merknad @Temporalfor å kontrollere tilordningen av 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 bruker TIMESTAMP- typen for å representere dem i databasen.

4.2 Ny tid

For tiden, med kartlegging, er alt mye enklere og bedre. Alle databaser støtter 4 typer data for å arbeide med tid:

  • DATO - dato: år, måned og dag.
  • TID - tid: timer, minutter, sekunder.
  • TIMESTAMP - dato, klokkeslett og nanosekunder.
  • TIDSSTEMPEL MED TIDSSONE - TIDSSTIMPEL og tidssone (sonenavn eller forskyvning).

For å representere typen DATOi Java må du bruke en klasse java.time.LocalDatefra JDK 8 DateTime API.

TypeTIDfra databasen kan representeres av to typer fra Java: java.time.LocalTimeog java.time.OffsetTime. Ikke noe komplisert.

Og nøyaktig dato og klokkeslett representert av typenTIDSSTIMPELi basen, i Java kan det representeres av 4 typer:

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

Og endeligTIDSSTIMPEL MED TIDSSONEkan representeres av to typer:

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

Siden du allerede er kjent med DateTime API , vil det ikke være vanskelig for deg å huske denne saken :)

Å kartlegge dem er ren nytelse:

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

Merknaden @Basicbetyr at feltet skal behandles automatisk : Hibernate vil bestemme hvilken kolonne og type dette feltet skal tilordnes.

4.3 Arbeide med tidssoner

Hvis tidssonen er en del av en dato, er det enkelt å lagre dem i databasen - akkurat som en vanlig dato:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Men hvis du vil lagre tidssoner separat fra datoen:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Da vil Hibernate lagre dem i VARCHAR-type som standard. Noe som faktisk er logisk, siden TimeZone vanligvis har et strengnavn som "UTC + 3" eller "Cairo".

4.4 Stille inn din egen tidssone

Når du jobber med å lagre datoer til databasen, vil du komme over det faktum at det allerede er 4 steder du kan stille inn gjeldende tidssone:

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

Hvis DBMS ikke spesifiserer en tidssone (TimeZone), vil den hente den fra operativsysteminnstillingene. Dette kan være upraktisk, siden backup-DBMS-er ofte er plassert i andre datasentre som har sin egen tidssone.

Derfor setter nesten alle DBMS-administratorer en enkelt sone slik at data enkelt kan overføres fra en server til en annen.

Situasjonen er lik med en Java-applikasjon. Den kan også kjøres på forskjellige servere i forskjellige datasentre, så den har vanligvis en eksplisitt tidssone.


java -Duser.timezone=UTC ...

Eller mens programmet kjører:

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

Og selvfølgelig lar Hibernate deg angi tidssonen eksplisitt.

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

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

For det andre kan tidssonen angisfor en bestemt økt:

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

4.5 @TimeZoneStorage-kommentar

Det hender ofte at programmerere begynte å designe en database basert på å jobbe i ett land (og én tidssone), og så etter et par år måtte de legge til støtte for å jobbe i forskjellige tidssoner.

Derfor la de ganske enkelt til en egen kolonne i databasen for å lagre tidssonen. Dette er en så vanlig situasjon at Hibernate har lagt til en spesiell merknad som lar deg lagre tidssonen for en bestemt dato i en egen 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 det er også en unnskyldning for det: det dukket opp på et tidspunkt da DateTime API ennå ikke eksisterte. Og det var umulig å lagre TimeZone i klassen java.util.Date.

Jeg håper virkelig at du ikke ofte ser dette i koden din.