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! :)