Obecny stan rzeczy w czasie
Od czasu wynalezienia JDBC i ujednolicenia jego interfejsów minęło 20 lat iw tym czasie wiele się zmieniło.
Po pierwsze, świat stał się globalny i teraz jeden serwer może obsługiwać użytkowników z całego świata. Szybkość internetu wzrosła. Dlatego do SQL dodano inny typ danych, aby pracować z czasem. Teraz typy wyglądają tak:
- DATA - przechowuje datę: rok, miesiąc, dzień.
- TIME - przechowuje czas: godziny, minuty, sekundy.
- TIMESTAMP - przechowuje określony punkt w czasie: datę, godzinę i milisekundy.
- TIMESTAMP WITH TIME ZONE - TIMESTAMP i strefa czasowa (nazwa strefy lub przesunięcie).
Po drugie, Java wprowadziła API DateTime do globalnego zarządzania czasem. Ma następujące klasy:
- Data i godzina :
- Data lokalna
- Czas lokalny
- Dokładny moment :
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
- Czas ze strefą czasową :
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Trzecią interesującą kwestią jest to, że wielu klientów SQL chciałoby otrzymywać czas z serwera znajdującego się już w ich strefie lokalnej . Oczywiście możesz konwertować czas w locie, ale nie jest to wygodne i zdarzają się błędy.
Na przykład chcę pobrać wszystkie zadania na dziś z bazy danych. SQL Server ma do tego funkcję CURDATE() . Tylko tutaj serwer jest w USA, a ja w Japonii. I chciałbym, żeby zwrócił wszystkie zapisy na „moje dzisiaj”, a nie „jego dzisiaj”.
Ogólnie rzecz biorąc, serwer SQL musi być w stanie inteligentnie współpracować z klientami w różnych strefach czasowych.
Współczesne problemy wymagają nowoczesnych rozwiązań
W zasadzie nowe typy z Java DateTime API i typy z SQL mogą być wygodnie mapowane. Aby reprezentować typ DATE w Javie, należy użyć klasy java.time.LocalDate z interfejsu API DateTime pakietu JDK 8.
Typ TIME z bazy danych może być reprezentowany przez dwa typy z Javy: java.time.LocalTime i java.time.OffsetTime . Nic skomplikowanego też.
Określony punkt w czasie, reprezentowany przez typ TIMESTAMP w bazie danych, może być reprezentowany w Javie przez 4 typy:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
I wreszcie TIMESTAMP WITH TIME ZONE może być reprezentowany przez dwa typy:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Ponieważ znasz już API DateTime, zapamiętanie tej kwestii nie będzie dla Ciebie trudne :)
Napiszę to w formie tabeli, więc będzie łatwiej:
TYP SQL | Typ Javy |
---|---|
DATA | java.time.LocalDate |
CZAS | java.time.LocalTime java.time.OffsetTime |
ZNAK CZASU | java.time.Instant java.time.LocalDateTime java.time.OffsetDateTime java.time.ZonedDateTime |
ZNACZNIK CZASU ZE STREFĄ CZASOWĄ | java.time.OffsetDateTime _ |
Uzyskiwanie daty
Mam dobre wiadomości dla Ciebie. Pierwszy od dłuższego czasu. Możemy obejść ograniczenia metody getDate() , która zwraca typ daty java.sql.
Rzecz w tym, że przedmiotzestaw wynikówjest jeszcze jedna interesująca metoda - getObject() . Ta metoda przyjmuje dwa parametry: kolumnę i typ oraz zwraca wartość kolumny przekonwertowanej na dany typ. Ogólna postać metody jest następująca:
ClassName Name = getObject(column, ClassName);
A jeśli chcesz przekonwertować typ DATE na typ java.time.LocalDate , musisz napisać coś takiego:
LocalDate localDate = results.getObject(4, LocalDate.class);
I ogólnie każdy TIMESTAMP można przekonwertować na kilka typów:
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);
Ważny! Ten kod nie zadziała, jeśli masz przestarzały sterownik MySQL JDBC . Zwróć uwagę na wersję „mysql-connector-java” zapisaną w pom.xml lub dodaną do Bibliotek w ustawieniach projektu.
Nawiasem mówiąc, w ten sam sposób można obejść brak możliwości przechowywania wartości null dla typów pierwotnych. Jeśli kolumna tabeli jest typu INT, istnieje kilka sposobów uzyskania z niej wartości null. Zobacz przykład poniżej:
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
Ustawienie strefy czasowej w MySQL
Wiele interesujących rzeczy wydarzyło się również z MySQL. Jak wiesz, podczas tworzenia połączenia MySQL możesz dodać do niego różne parametry :mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning
Tak więc dodano trzy parametry do pracy ze strefami czasowymi w MySQL. Parametry te można przekazać podczas nawiązywania połączenia z serwerem.
Poniżej podam tabelkę z nimi:
Parametr | Wartości | Domyślna wartość |
---|---|---|
połączenieStrefa Czasowa | LOKALNE | SERWER | strefa użytkownika | SERWER |
forceConnectionTimeZoneToSession | prawda | FAŁSZ | PRAWDA |
zachowajInstancje | prawda | FAŁSZ | FAŁSZ |
Za pomocą parametru connectionTimeZone wybieramy strefę czasową (strefę czasową), w której będą wykonywane wszystkie żądania. Z punktu widzenia klienta serwer działa w określonej strefie czasowej.
Parametr forceConnectionTimeZoneToSession powoduje, że zmienna time_zone sesji jest ignorowana i zastępowana przez connectionTimeZone.
Na koniec parametr keepInstants steruje konwersją dokładnego czasu między strefą czasową maszyny JVM a strefą czasową połączenia.
Najczęstsze konfiguracje to:
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - odpowiada staremu sterownikowi MySQL JDBC w wersji 5.1 z useLegacyDatetimeCode=true.
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true to nowy tryb, który zapewnia najbardziej naturalny sposób obsługi wartości daty i godziny.
-
connectionTimeZone=SERVER &serverInstants=true — Odpowiada staremu sterownikowi JDBC MySQL w wersji 5.1 z parametrem useLegacyDatetimeCode=false.
-
connectionTimeZone=user_defined & keepInstants=true — pomaga przezwyciężyć sytuację, w której strefa czasowa serwera nie może zostać rozpoznana przez łącznik, ponieważ jest ustawiona jako ogólny skrót, taki jak CET/CEST.
Tak, daty to ciekawy temat i jest z nimi wiele problemów. Jak to się mówi: to straszne, oczywiście, ale też nie jestem wkurzony! :)
GO TO FULL VERSION