De huidige stand van zaken in de tijd

Sinds de tijd dat JDBC werd uitgevonden en de interfaces werden gestandaardiseerd, zijn er 20 jaar verstreken en in die tijd zijn er veel dingen veranderd.

Ten eerste is de wereld mondiaal geworden en nu kan één server gebruikers van over de hele wereld bedienen. De internetsnelheid is omhoog. Daarom is er een ander gegevenstype aan SQL toegevoegd om met de tijd te werken. Nu zien de typen er als volgt uit:

  • DATE - slaat de datum op: jaar, maand, dag.
  • TIME - slaat tijd op: uren, minuten, seconden.
  • TIMESTAMP - slaat een specifiek tijdstip op: datum, tijd en milliseconden.
  • TIJDSTAMP MET TIJDZONE - TIJDSTAMP en tijdzone (zonenaam of offset).

Ten tweede introduceerde Java de DateTime API voor wereldwijd tijdbeheer. Het heeft de volgende klassen:

  • Datum en tijd :
    • LokaleDatum
    • Lokale tijd
  • Exact moment :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Tijd met tijdzone :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Het derde interessante punt is dat veel SQL-clients tijd willen ontvangen van de server die zich al in hun lokale zone bevindt . Natuurlijk kun je de tijd direct omrekenen, maar het is niet handig en er zijn fouten.

Ik wil bijvoorbeeld alle taken voor vandaag uit de database halen. SQL Server heeft hiervoor een CURDATE() functie. Alleen hier is de server in de VS en ik in Japan. En ik zou graag willen dat hij alle records terugstuurt voor "mijn vandaag", en niet "zijn vandaag".

Over het algemeen moet de SQL-server ook slim kunnen werken met clients in verschillende tijdzones.

Moderne problemen vragen om moderne oplossingen

In principe kunnen nieuwe typen uit de Java DateTime API en typen uit SQL gemakkelijk in kaart worden gebracht. Om het type DATE in Java weer te geven, moet u de klasse java.time.LocalDate uit de JDK 8 DateTime API gebruiken .

Het TIME-type uit de database kan worden weergegeven door twee typen uit Java: java.time.LocalTime en java.time.OffsetTime . Ook niets ingewikkelds.

Een specifiek tijdstip, vertegenwoordigd door het type TIMESTAMP in de database, kan in Java worden weergegeven door 4 typen:

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

En tot slot kan TIJDSTAMP MET TIJDZONE 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 :)

Ik zal het in de vorm van een tabel schrijven, dus het zal gemakkelijker zijn:

SQL-TYPE Java-type
DATUM java.time.LocalDate
TIJD java.time.LocalTime
java.time.OffsetTime
TIJDSTAMP java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
TIJDSTAMP MET TIJDZONE java.time.OffsetDateTime
_

De datum ophalen

Ik heb goed nieuws voor je. Eerst sinds lange tijd. We kunnen de beperking van de methode getDate() omzeilen , die een java.sql-datumtype retourneert.

Het punt is dat het objectresultaat ingestelder is nog een interessante methode - getObject() . Deze methode heeft twee parameters nodig: een kolom en een type, en retourneert de waarde van de kolom geconverteerd naar het gegeven type. De algemene vorm van de methode is als volgt:

ClassName Name = getObject(column, ClassName);

En als u het type DATE naar het type java.time.LocalDate wilt converteren , moet u iets schrijven als:

LocalDate localDate = results.getObject(4, LocalDate.class);

En elke TIMESTAMP in het algemeen kan worden geconverteerd naar een aantal typen:

java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);

Belangrijk! Deze code werkt niet als u een verouderde MySQL JDBC-driver heeft . Let op de versie van "mysql-connector-java" geschreven in uw pom.xml, of toegevoegd aan de bibliotheken in de projectinstellingen.

Trouwens, op dezelfde manier kun je het onvermogen om null op te slaan voor primitieve typen omzeilen. Als een tabelkolom van het type INT is, zijn er een aantal manieren om er null uit te halen. Zie voorbeeld hieronder:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

Tijdzone-instelling in MySQL

Er gebeurden ook veel interessante dingen met MySQL. Zoals u weet, kunt u bij het maken van een MySQL-verbinding verschillende parameters toevoegen :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Er zijn dus drie parameters toegevoegd om te werken met tijdzones in MySQL. U kunt deze parameters doorgeven wanneer u een verbinding met de server tot stand brengt.

Hieronder zal ik een tabel met hen geven:

Parameter Waarden Standaardwaarde
verbindingTimeZone LOKAAL | DIENST | gebruikerszone SERVER
forceConnectionTimeZoneToSession waar | vals WAAR
bewaarInstants waar | vals vals

Met behulp van de parameter connectionTimeZone selecteren we de tijdzone (tijdzone) waarin alle verzoeken worden uitgevoerd. Vanuit het oogpunt van de klant draait de server in de opgegeven tijdzone.

De parameter forceConnectionTimeZoneToSession zorgt ervoor dat de variabele session time_zone wordt genegeerd en vervangen door connectionTimeZone.

Ten slotte regelt de parameter preserveInstants de exacte tijdconversie tussen de JVM's timeZone en connectionTimeZone.

De meest voorkomende configuraties zijn:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - komt overeen met de oude MySQL JDBC driver versie 5.1 met useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true is een nieuwe modus die de meest natuurlijke manier biedt om datum- en tijdwaarden te verwerken.

  • connectionTimeZone=SERVER & preserveInstants=true - Komt overeen met het oude MySQL JDBC-stuurprogramma versie 5.1 met useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Helpt de situatie te overwinnen waarin de tijdzone van de server niet kan worden herkend door de connector omdat deze is ingesteld als een generieke afkorting zoals CET/CEST.

Ja, dates zijn een interessant onderwerp en er zijn veel problemen mee. Zoals het spreekwoord zegt: het is natuurlijk eng, maar ik ben ook niet boos! :)