Starea actuală de-a lungul timpului
De când a fost inventat JDBC și interfețele sale au fost standardizate, au trecut 20 de ani, iar în acest timp s-au schimbat multe lucruri.
În primul rând, lumea a devenit globală și acum un server poate servi utilizatori din întreaga lume. Viteza internetului este crescută. Prin urmare, un alt tip de date a fost adăugat la SQL pentru a funcționa cu timpul. Acum tipurile arată astfel:
- DATA - stochează data: an, lună, zi.
- TIME - stochează timpul: ore, minute, secunde.
- TIMESTAMP - stochează un anumit punct de timp: data, ora și milisecunde.
- TIMESTAMP WITH TIME ZONE - TIMESTAMP și fus orar (numele sau decalajul zonei).
În al doilea rând, Java a introdus API-ul DateTime pentru gestionarea globală a timpului. Are următoarele clase:
- Data si ora :
- LocalDate
- Ora locala
- Momentul exact :
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
- Ora cu fusul orar :
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Al treilea punct interesant este că mulți clienți SQL ar dori să primească timp de la server deja în zona lor locală . Desigur, puteți converti timpul din mers, dar nu este convenabil și există greșeli.
De exemplu, vreau să obțin toate sarcinile pentru azi din baza de date. SQL Server are o funcție CURDATE() pentru aceasta. Doar aici serverul este în SUA, iar eu sunt în Japonia. Și mi-aș dori să returneze toate înregistrările pentru „azi a mea”, și nu pentru „azi a lui”.
În general, serverul SQL trebuie, de asemenea, să poată lucra inteligent cu clienții din diferite fusuri orare.
Problemele moderne necesită soluții moderne
În principiu, tipurile noi din API-ul Java DateTime și tipurile din SQL pot fi mapate în mod convenabil. Pentru a reprezenta tipul DATE în Java, trebuie să utilizați clasa java.time.LocalDate din API-ul JDK 8 DateTime.
Tipul TIME din baza de date poate fi reprezentat de două tipuri din Java: java.time.LocalTime și java.time.OffsetTime . Nimic complicat nici.
Un anumit moment în timp, reprezentat de tipul TIMESTAMP din baza de date, poate fi reprezentat în Java prin 4 tipuri:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Și, în sfârșit, TIMESTAMP CU TIME ZONE poate fi reprezentat de două tipuri:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Deoarece sunteți deja familiarizat cu API-ul DateTime, să vă amintiți această problemă nu vă va fi dificil :)
O voi scrie sub forma unui tabel, așa că va fi mai ușor:
TIP SQL | Tipul Java |
---|---|
DATA | java.time.LocalDate |
TIMP | java.time.LocalTime java.time.OffsetTime |
TIMESTAMP-UL | java.time.Instant java.time.LocalDateTime java.time.OffsetDateTime java.time.ZonedDateTime |
TIMESTAMP CU FUS ORAR | java.time.OffsetDateTime _ |
Obținerea datei
Am o veste bună pentru tine. Prima după mult timp. Putem ocoli limitarea metodei getDate() , care returnează un tip de date java.sql.
Ideea este că obiectulsetul de rezultateexistă o altă metodă interesantă - getObject() . Această metodă ia doi parametri: o coloană și un tip și returnează valoarea coloanei convertită la tipul dat. Forma generală a metodei este următoarea:
ClassName Name = getObject(column, ClassName);
Și dacă doriți să convertiți tipul DATE în tipul java.time.LocalDate , atunci trebuie să scrieți ceva de genul:
LocalDate localDate = results.getObject(4, LocalDate.class);
Și orice TIMESTAMP în general poate fi convertit într-o mulțime de tipuri:
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);
Important! Acest cod nu va funcționa dacă aveți un driver JDBC MySQL învechit . Fiți atenți la versiunea „mysql-connector-java” scrisă în pom.xml sau adăugată în biblioteci în setările proiectului.
Apropo, în același mod, puteți ocoli incapacitatea de a stoca null pentru tipurile primitive. Dacă o coloană de tabel este de tip INT, atunci există câteva moduri de a obține nul de la ea. Vezi exemplul de mai jos:
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
Setarea fusului orar în MySQL
S-au întâmplat multe lucruri interesante și cu MySQL. După cum știți, atunci când creați o conexiune MySQL, îi puteți adăuga diferiți parametri :mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning
Deci, au fost adăugați trei parametri pentru a funcționa cu fusurile orare în MySQL. Puteți transmite acești parametri atunci când stabiliți o conexiune la server.
Mai jos voi da un tabel cu ei:
Parametru | Valori | Valoare implicită |
---|---|---|
connectionTimeZone | LOCAL | SERVER | zona utilizator | SERVER |
forceConnectionTimeZoneToSession | adevărat | fals | Adevărat |
preserveInstants | adevărat | fals | fals |
Folosind parametrul connectionTimeZone , selectăm fusul orar (fus orar) în care vor fi executate toate solicitările. Din punctul de vedere al clientului, serverul rulează în fusul orar specificat.
Parametrul forceConnectionTimeZoneToSession face ca variabila time_zone de sesiune să fie ignorată și înlocuită cu connectionTimeZone.
În cele din urmă, parametrul preserveInstants controlează conversia exactă a timpului dintre fusul orar al JVM-ului și connectionTimeZone.
Cele mai comune configurații sunt:
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - corespunde vechiului driver MySQL JDBC versiunea 5.1 cu useLegacyDatetimeCode=true.
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true este un mod nou care oferă cel mai natural mod de a gestiona valorile datei și orei.
-
connectionTimeZone=SERVER & preserveInstants=true - Corespunde vechiului driver MySQL JDBC versiunea 5.1 cu useLegacyDatetimeCode=false.
-
connectionTimeZone=user_defined & preserveInstants=true - Ajută la depășirea situației în care fusul orar al serverului nu poate fi recunoscut de către conector, deoarece este setat ca o abreviere generică, cum ar fi CET/CEST.
Da, întâlnirile sunt un subiect interesant și sunt multe probleme cu ele. După cum se spune: e înfricoșător, desigur, dar nici eu nu sunt supărat! :)
GO TO FULL VERSION