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 @Temporal
for å 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.Calendar
og java.util.Date
standardtypen 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.LocalDate
fra JDK 8 DateTime API.
TypeTIDfra databasen kan representeres av to typer fra Java: java.time.LocalTime
og 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 @Basic
betyr 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.