4.1 Excursie in de geschiedenis

De taak van het opslaan van Java-objecten in de database was vrijwel onmiddellijk relevant na het maken van de Java-taal. Op dat moment was er in de Java-taal maar één gegevenstype, Date, dat de tijd opsloeg volgens de UNIX-tijdstandaard: als het aantal milliseconden sinds 1970.

Welnu, in de databases van die tijd waren er al verschillende datatypes voor datums, althans er waren aparte types voor datum, tijd en datum + tijd:

  • DATUM
  • TIJD
  • TIJDSTAMP

Daarom hebben de makers van de Java-taal er een speciaal pakket aan toegevoegd - java.sql, dat klassen bevatte:

  • java.sql.datum
  • java.sql.Tijd
  • java.sql.tijdstempel

Het in kaart brengen van deze klassen is een waar genoegen:


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

Maar aangezien programmeurs vroeger met de klasse werkten java.util.Date, heeft Hibernate een speciale annotatie toegevoegd @Temporalom de toewijzing van het datumtype te regelen.

Voorbeeld:

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

Het type java.util.Calendaren java.util.Datestandaardtype gebruiken het TIMESTAMP- type om ze in de database weer te geven.

4.2 Nieuwe tijd

Op dit moment is alles met mapping veel eenvoudiger en beter. Alle databases ondersteunen 4 soorten gegevens om met de tijd te werken:

  • DATUM - datum: jaar, maand en dag.
  • TIJD - tijd: uren, minuten, seconden.
  • TIMESTAMP - datum, tijd en nanoseconden.
  • TIJDSTAMP MET TIJDZONE - TIJDSTAMP en tijdzone (zonenaam of offset).

Om het type weer te geven DATUMjava.time.LocalDatein Java moet u een klasse van de JDK 8 DateTime API gebruiken .

TypeTIJDuit de database kan worden weergegeven door twee typen uit Java: java.time.LocalTimeen java.time.OffsetTime. Niets ingewikkelds.

En de exacte datum en tijd vertegenwoordigd door het typeTIJDSTAMPin de basis kan het in Java worden weergegeven door 4 typen:

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

En tenslotteTIJDSTAMP MET TIJDZONEkan worden weergegeven door twee typen:

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

Aangezien u al bekend bent met de DateTime API , zal het niet moeilijk voor u zijn om deze kwestie te onthouden :)

Het in kaart brengen ervan is puur plezier:

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

De annotatie @Basicbetekent dat het veld automatisch moet worden verwerkt : Hibernate zal beslissen op welke kolom en type dit veld moet worden toegewezen.

4.3 Werken met tijdzones

Als de tijdzone deel uitmaakt van een datum, is het eenvoudig om deze in de database op te slaan, net als bij een gewone datum:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Als u echter tijdzones apart van de datum wilt opslaan:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Dan slaat Hibernate ze standaard op in VARCHAR-type. Wat in feite logisch is, aangezien de TimeZone meestal een stringnaam heeft zoals "UTC + 3" of "Cairo".

4.4 Uw eigen tijdzone instellen

Wanneer u werkt met het opslaan van datums in de database, zult u merken dat er al 4 plaatsen zijn waar u de huidige tijdzone kunt instellen:

  • Serverbesturingssysteem;
  • DBMS;
  • Java-toepassing
  • Overwinteren.

Als het DBMS geen tijdzone (TimeZone) specificeert, wordt deze overgenomen uit de instellingen van het besturingssysteem. Dit kan onhandig zijn, aangezien back-up-DBMS'en zich vaak in andere datacenters bevinden die hun eigen tijdzone hebben.

Daarom stellen bijna alle DBMS-beheerders een enkele zone in, zodat gegevens eenvoudig van de ene server naar de andere kunnen worden overgedragen.

De situatie is vergelijkbaar met een Java-toepassing. Het kan ook op verschillende servers in verschillende datacenters worden uitgevoerd, dus het heeft meestal een expliciete tijdzone.


java -Duser.timezone=UTC ...

Of terwijl het programma draait:

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

En natuurlijk kunt u met Hibernate uw tijdzone expliciet instellen.

Ten eerste kan het worden opgegeven bij het configureren van de SessionFactory:

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

Ten tweede kan de tijdzone worden opgegevenvoor een bepaalde sessie:

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

4.5 @TimeZoneStorage-annotatie

Het komt vaak voor dat programmeurs begonnen met het ontwerpen van een database op basis van werken in één land (en één tijdzone), en na een paar jaar moesten ze ondersteuning toevoegen voor het werken in verschillende tijdzones.

Daarom hebben ze gewoon een aparte kolom aan de database toegevoegd om de tijdzone op te slaan. Dit komt zo vaak voor dat Hibernate een speciale annotatie heeft toegevoegd waarmee je de TimeZone van een specifieke datum in een aparte kolom kunt opslaan.

Voorbeeld:

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

Dit is een kruk. Maar er is ook een excuus voor: het verscheen in een tijd dat de DateTime API nog niet bestond. En het was onmogelijk om TimeZone op te slaan in de klas java.util.Date.

Ik hoop echt dat je dit niet vaak in je code zult zien.