4.1 Utflykt till historien
Uppgiften att spara Java-objekt i databasen var relevant nästan omedelbart efter skapandet av Java-språket. På den tiden fanns det bara en datatyp i Java-språket, Date, som lagrade tid enligt UNIX-tidsstandarden: som antalet millisekunder sedan 1970.
Tja, i databaserna på den tiden fanns det redan olika datatyper för datum, åtminstone fanns det separata typer för datum, tid och datum + tid:
- DATUM
- TID
- TIDSSTÄMPEL
Därför lade skaparna av Java-språket till ett speciellt paket till det - java.sql, som innehöll klasser:
- java.sql.date
- java.sql.Time
- java.sql.timestamp
Att kartlägga dessa klasser är ett sant nöje:
@Entity
public class TemporalValues {
@Basic
private java.sql.Date sqlDate;
@Basic
private java.sql.Time sqlTime;
@Basic
private java.sql.Timestamp sqlTimestamp;
}
Men eftersom programmerare brukade arbeta med klassen java.util.Date
lade Hibernate till en speciell anteckning @Temporal
för att kontrollera mappningen av datumtypen.
Exempel:
// 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
och java.util.Date
standardtypen använder TIMESTAMP -typen för att representera dem i databasen.
4.2 Ny tid
För närvarande, med kartläggning, är allt mycket enklare och bättre. Alla databaser stöder 4 typer av data att arbeta med tiden:
- DATUM - datum: år, månad och dag.
- TID - tid: timmar, minuter, sekunder.
- TIMESTAMP - datum, tid och nanosekunder.
- TIDSTÄMPEL MED TIDZON - TIDSTÄMPEL och tidszon (zonnamn eller offset).
För att representera typen DATUMi Java måste du använda en klass java.time.LocalDate
från JDK 8 DateTime API.
TypTIDfrån databasen kan representeras av två typer från Java: java.time.LocalTime
och java.time.OffsetTime
. Inget komplicerat.
Och exakt datum och tid som representeras av typenTIDSSTÄMPELi basen, i Java kan det representeras av 4 typer:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Och slutligenTIDSTÄMPEL MED TIDZONkan representeras av två typer:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Eftersom du redan är bekant med DateTime API kommer det inte att vara svårt för dig att komma ihåg denna fråga :)
Att kartlägga dem är rent nöje:
@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;
Anteckningen @Basic
innebär att fältet ska bearbetas automatiskt : Hibernate kommer att bestämma vilken kolumn och typ detta fält ska mappas.
4.3 Arbeta med tidszoner
Om tidszonen är en del av ett datum är det enkelt att lagra dem i databasen - precis som ett vanligt datum:
@Basic
private java.time.OffsetDateTime offsetDateTime;
@Basic
private java.time.ZonedDateTime zonedDateTime;
Men om du vill lagra tidszoner separat från datumet:
@Basic
private java.time.TimeZone timeZone;
@Basic
private java.time.ZoneOffset zonedOffset;
Då lagrar Hibernate dem i VARCHAR-typ som standard. Vilket faktiskt är logiskt, eftersom TimeZone vanligtvis har ett strängnamn som "UTC + 3" eller "Cairo".
4.4 Ställa in din egen tidszon
När du arbetar med att spara datum till databasen kommer du att stöta på att det redan finns 4 platser där du kan ställa in aktuell tidszon:
- Serveroperativsystem;
- DBMS;
- Java-applikation
- Övervintra.
Om DBMS inte anger en tidszon (TimeZone), kommer den att ta den från operativsystemets inställningar. Detta kan vara obekvämt, eftersom backup-DBMS ofta finns i andra datacenter som har sin egen tidszon.
Därför ställer nästan alla DBMS-administratörer in en enda zon så att data enkelt kan överföras från en server till en annan.
Situationen är liknande med en Java-applikation. Den kan också köras på olika servrar i olika datacenter, så den har vanligtvis en explicit tidszon.
java -Duser.timezone=UTC ...
Eller medan programmet körs:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Och naturligtvis låter Hibernate dig explicit ställa in din tidszon.
Först kan det specificeras när du konfigurerar SessionFactory:
settings.put(
AvailableSettings.JDBC_TIME_ZONE,
TimeZone.getTimeZone("UTC")
);
För det andra kan tidszonen specificerasför en specifik session:
Session session = sessionFactory()
.withOptions()
.jdbcTimeZone(TimeZone.getTimeZone("UTC"))
.openSession();
4.5 @TimeZoneStorage-anteckning
Det händer ofta att programmerare började designa en databas baserad på att arbeta i ett land (och en tidszon), och sedan efter ett par år behövde de lägga till stöd för att arbeta i olika tidszoner.
Därför lade de helt enkelt till en separat kolumn i databasen för att lagra tidszonen. Detta är en så vanlig situation att Hibernate har lagt till en speciell anteckning som låter dig lagra tidszonen för ett specifikt datum i en separat kolumn.
Exempel:
@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;
Det här är en krycka. Men det finns också en ursäkt för det: det dök upp vid en tidpunkt då DateTime API ännu inte existerade. Och det var omöjligt att lagra TimeZone i klassen java.util.Date
.
Jag hoppas verkligen att du inte kommer att se detta ofta i din kod.
GO TO FULL VERSION