A dolgok jelenlegi állása idővel

A JDBC feltalálása és interfészeinek szabványosítása óta 20 év telt el, és ezalatt sok minden megváltozott.

Először is, a világ globálissá vált, és most egyetlen szerver képes kiszolgálni a felhasználókat a világ minden tájáról. Növekszik az internet sebessége. Ezért egy másik adattípus került az SQL-be, hogy az idővel működjön. A típusok most így néznek ki:

  • DÁTUM – tárolja a dátumot: év, hónap, nap.
  • IDŐ – tárolja az időt: órák, percek, másodpercek.
  • TIMESTAMP – egy adott időpontot tárol: dátum, idő és ezredmásodperc.
  • IDŐBÉLYEG IDŐZÓVAL - IDŐBÉLYEGZET és időzóna (zóna neve vagy eltolás).

Másodszor, a Java bevezette a DateTime API-t a globális időkezeléshez. A következő osztályokkal rendelkezik:

  • Dátum és idő :
    • LocalDate
    • Helyi idő
  • Pontos pillanat :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Idő az időzónával :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

A harmadik érdekesség az, hogy sok SQL kliens szeretne időt kapni a helyi zónájában lévő szervertől . Természetesen menet közben is át lehet konvertálni az időt, de ez nem kényelmes, és vannak hibák.

Például a mai nap összes feladatát szeretném lekérni az adatbázisból. Az SQL Server rendelkezik erre a CURDATE() függvényrel. Csak itt a szerver az USA-ban van, én pedig Japánban. És szeretném, ha visszaadná az összes lemezt az „én mai napom” címére, és nem „az övé a mai”.

Általánosságban elmondható, hogy az SQL szervernek képesnek kell lennie arra is, hogy okosan működjön együtt a különböző időzónákban lévő ügyfelekkel.

A modern problémák modern megoldásokat igényelnek

Elvileg a Java DateTime API új típusai és az SQL-ből származó típusok kényelmesen leképezhetők. A DATE típus Java-ban való megjelenítéséhez a java.time.LocalDate osztályt kell használnia a JDK 8 DateTime API-ból.

Az adatbázisból származó TIME típust két Java típus képviselheti: java.time.LocalTime és java.time.OffsetTime . Semmi bonyolult sem.

Egy adott időpont, amelyet az adatbázisban a TIMESTAMP típus képvisel , a Java nyelven 4 típussal ábrázolható:

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

És végül, az IDŐZÓNA IDŐBÉLYEGZÉS kétféleképpen ábrázolható:

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

Mivel már ismeri a DateTime API-t, nem lesz nehéz megjegyezni ezt a dolgot :)

Leírom táblázat formájában, így könnyebb lesz:

SQL TÍPUS Java típus
DÁTUM java.time.LocalDate
IDŐ java.time.LocalTime
java.time.OffsetTime
IDŐBÉLYEG java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
IDŐBÉLYEG IDŐZÓNÁVAL java.time.OffsetDateTime
_

A dátum megszerzése

Van egy jó hírem számodra. Hosszú idő óta először. Megkerülhetjük a getDate() metódus korlátozását , amely java.sql dátumtípust ad vissza.

A lényeg az, hogy a tárgyeredménykészletvan egy másik érdekes módszer - getObject() . Ez a metódus két paramétert vesz fel: egy oszlopot és egy típust, és az oszlop adott típusra konvertált értékét adja vissza. A módszer általános formája a következő:

ClassName Name = getObject(column, ClassName);

Ha pedig a DATE típust java.time.LocalDate típusra szeretné konvertálni , akkor valami ilyesmit kell írnia:

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

És általában minden TIMESTAMP átalakítható egy csomó típusra:

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

Fontos! Ez a kód nem fog működni, ha elavult MySQL JDBC illesztőprogramja van . Ügyeljen a „mysql-connector-java” pom.xml fájlba írt verziójára, vagy a projektbeállítások könyvtáraihoz adott verziójára.

Egyébként ugyanígy megkerülhető a primitív típusok null tárolásának képtelensége is. Ha egy táblázat oszlopa INT típusú, akkor több módon is null értéket kaphatunk belőle. Lásd az alábbi példát:

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

Időzóna beállítása a MySQL-ben

A MySQL-lel is sok érdekes dolog történt. Mint tudod, a MySQL-kapcsolat létrehozásakor különféle paramétereket adhat hozzá :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Tehát három paramétert adtunk hozzá az időzónákkal való együttműködéshez a MySQL-ben. Ezeket a paramétereket átadhatja, amikor kapcsolatot létesít a szerverrel.

Az alábbiakban adok egy táblázatot velük:

Paraméter Értékek Alapértelmezett érték
connectTimeZone HELYI | SZERVER | felhasználói zóna SZERVER
forceConnectionTimeZoneToSession igaz | hamis igaz
KeepInstants igaz | hamis hamis

A connectionTimeZone paraméter segítségével kiválasztjuk azt az időzónát (időzónát), amelyben az összes kérés végrehajtásra kerül. A kliens szempontjából a szerver a megadott időzónában fut.

A forceConnectionTimeZoneToSession paraméter hatására a rendszer figyelmen kívül hagyja a session time_zone változót, és a connectTimeZone-ra cseréli.

Végül a konservInstants paraméter vezérli a pontos idő-konverziót a JVM időzónája és a connectionTimeZone között.

A leggyakoribb konfigurációk a következők:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false – a régi MySQL JDBC illesztőprogram 5.1-es verziójának felel meg, ahol useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true egy új mód, amely a dátum- és időértékek kezelésének legtermészetesebb módját biztosítja.

  • connectionTimeZone=SZERVER & konservInstants=true – Megfelel a régi MySQL JDBC illesztőprogram 5.1-es verziójának, a useLegacyDatetimeCode=false értékkel.

  • connectionTimeZone=user_defined & konservInstants=true – Segít leküzdeni azt a helyzetet, amikor a kiszolgáló időzónáját nem ismeri fel az összekötő, mert az általános rövidítésként van beállítva, például CET/CEST.

Igen, a dátumok érdekes téma, és sok probléma van velük. Ahogy a mondás tartja: ijesztő persze, de én sem vagyok mérges! :)