Ang kasalukuyang estado ng mga pangyayari sa paglipas ng panahon

Mula noong naimbento ang JDBC at na-standardize ang mga interface nito, 20 taon na ang lumipas, at sa panahong ito maraming bagay ang nagbago.

Una, ang mundo ay naging pandaigdigan at ngayon ang isang server ay maaaring maghatid ng mga user mula sa buong mundo. Ang bilis ng internet. Samakatuwid, ang isa pang uri ng data ay idinagdag sa SQL upang gumana sa oras. Ngayon ang mga uri ay ganito ang hitsura:

  • DATE - iniimbak ang petsa: taon, buwan, araw.
  • TIME - nag-iimbak ng oras: oras, minuto, segundo.
  • TIMESTAMP - nag-iimbak ng isang partikular na punto sa oras: petsa, oras at millisecond.
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP at time zone (pangalan ng zone o offset).

Pangalawa, ipinakilala ng Java ang DateTime API para sa pandaigdigang pamamahala ng oras. Mayroon itong mga sumusunod na klase:

  • Petsa at oras :
    • LocalDate
    • Lokal na Oras
  • Eksaktong sandali :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Oras na may time zone :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Ang ikatlong kawili-wiling punto ay maraming mga kliyente ng SQL ang gustong makatanggap ng oras mula sa server na nasa kanilang lokal na sona . Siyempre, maaari mong i-convert ang oras sa mabilisang, ngunit hindi ito maginhawa, at may mga pagkakamali.

Halimbawa, gusto kong makuha ang lahat ng mga gawain para sa araw na ito mula sa database. Ang SQL Server ay may CURDATE() function para dito. Dito lang sa USA ang server, at nasa Japan ako. At gusto kong ibalik niya ang lahat ng mga tala para sa "aking ngayon", at hindi "kanya ngayon".

Sa pangkalahatan, ang SQL server ay dapat ding makapagtrabaho nang matalino sa mga kliyente sa iba't ibang time zone.

Ang mga modernong problema ay nangangailangan ng mga modernong solusyon

Sa prinsipyo, ang mga bagong uri mula sa Java DateTime API at mga uri mula sa SQL ay maaaring madaling ma-map. Upang kumatawan sa uri ng DATE sa Java, kailangan mong gamitin ang klase ng java.time.LocalDate mula sa JDK 8 DateTime API.

Ang uri ng TIME mula sa database ay maaaring katawanin ng dalawang uri mula sa Java: java.time.LocalTime at java.time.OffsetTime . Wala ring kumplikado.

Ang isang tiyak na punto ng oras, na kinakatawan ng uri ng TIMESTAMP sa database, ay maaaring katawanin sa Java ng 4 na uri:

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

At panghuli, ang TIMESTAMP WITH TIME ZONE ay maaaring katawanin ng dalawang uri:

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

Dahil pamilyar ka na sa DateTime API, ang pag-alala sa bagay na ito ay hindi magiging mahirap para sa iyo :)

Isusulat ko ito sa anyo ng isang talahanayan, kaya magiging mas madali:

URI ng SQL Uri ng Java
DATE java.time.LocalDate
ORAS java.time.LocalTime
java.time.OffsetTime
TIMESTAMP java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
TIMESTAMP NA MAY TIME ZONE java.time.OffsetDateTime
_

Pagkuha ng petsa

May magandang balita ako sa iyo. Una sa mahabang panahon. Malalampasan natin ang limitasyon ng getDate() method , na nagbabalik ng java.sql Date type.

Ang punto ay ang bagayset ng resultamay isa pang kawili-wiling paraan - getObject() . Ang pamamaraang ito ay tumatagal ng dalawang parameter: isang column at isang uri, at ibinabalik ang halaga ng column na na-convert sa ibinigay na uri. Ang pangkalahatang anyo ng pamamaraan ay ang mga sumusunod:

ClassName Name = getObject(column, ClassName);

At kung gusto mong i-convert ang uri ng DATE sa uri ng java.time.LocalDate , kailangan mong magsulat ng isang bagay tulad ng:

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

At anumang TIMESTAMP sa pangkalahatan ay maaaring ma-convert sa isang grupo ng mga uri:

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

Mahalaga! Hindi gagana ang code na ito kung mayroon kang isang lumang MySQL JDBC Driver . Bigyang-pansin ang bersyon ng "mysql-connector-java" na nakasulat sa iyong pom.xml, o idinagdag sa Mga Aklatan sa mga setting ng proyekto.

Sa pamamagitan ng paraan, sa parehong paraan, maaari mong libutin ang kawalan ng kakayahan na mag-imbak ng null para sa mga primitive na uri. Kung ang isang haligi ng talahanayan ay may uri ng INT, pagkatapos ay mayroong ilang mga paraan upang makakuha ng null mula dito. Tingnan ang halimbawa sa ibaba:

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

Setting ng timezone sa MySQL

Maraming mga kagiliw-giliw na bagay ang nangyari sa MySQL. Tulad ng alam mo, kapag lumilikha ng isang koneksyon sa MySQL, maaari kang magdagdag ng iba't ibang mga parameter dito :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Kaya, tatlong mga parameter ang naidagdag upang gumana sa mga time zone sa MySQL. Maaari mong ipasa ang mga parameter na ito kapag nagtatag ka ng koneksyon sa server.

Sa ibaba ay magbibigay ako ng isang mesa sa kanila:

Parameter Mga halaga Default na halaga
koneksyonTimeZone LOKAL | SERVER | user-zone SERVER
forceConnectionTimeZoneToSession totoo | mali totoo
preserveInstant totoo | mali mali

Gamit ang parameter na connectionTimeZone , pipiliin namin ang time zone (time zone) kung saan isasagawa ang lahat ng kahilingan. Mula sa pananaw ng kliyente, tumatakbo ang server sa tinukoy na time zone.

Ang parameter na forceConnectionTimeZoneToSession ay nagdudulot ng pagbalewala sa variable ng session time_zone at papalitan ng connectionTimeZone.

Panghuli, kinokontrol ng parameter ng preserveInstants ang eksaktong-time-conversion sa pagitan ng timeZone at connectionTimeZone ng JVM.

Ang pinakakaraniwang mga pagsasaayos ay:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - tumutugma sa lumang MySQL JDBC driver version 5.1 na may useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true ay isang bagong mode na nagbibigay ng pinaka natural na paraan upang mahawakan ang mga halaga ng petsa at oras.

  • connectionTimeZone=SERVER & preserveInstants=true - Tumutugma sa lumang MySQL JDBC driver version 5.1 na may useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Tumutulong na malampasan ang sitwasyon kung saan ang time zone ng server ay hindi makikilala ng connector dahil nakatakda ito bilang isang generic na pagdadaglat tulad ng CET/CEST.

Oo, ang mga petsa ay isang kawili-wiling paksa at maraming problema sa kanila. Sabi nga sa kasabihan: nakakatakot siyempre pero hindi rin naman ako naasar! :)