java.util.Date
vs java.sql.Date
: kiedy i z którego korzystać?
Gratulacje, trafiłeś w moją ulubioną psotkę z JDBC: obsługa klasy randkowej.
Zasadniczo bazy danych zwykle obsługują co najmniej trzy formy pól datetime, którymi są data, godzina i znacznik czasu. Każda z nich ma odpowiednią klasę w JDBC i każda z nich ma rozszerzeniejava.util.Date
. Szybka semantyka każdego z tych trzech jest następująca:
java.sql.Date
odpowiada SQL DATE, co oznacza, że przechowuje lata, miesiące i dni, a godzina, minuta, sekunda i milisekunda są ignorowane. Dodatkowo sql.Date
nie jest związany ze strefami czasowymi.java.sql.Time
odpowiada CZASOWI SQL i jak powinno być oczywiste, zawiera tylko informacje o godzinie, minutach, sekundach i milisekundach .java.sql.Timestamp
odpowiada SQL TIMESTAMP, który jest dokładną datą w nanosekundach ( pamiętaj, że util.Date
obsługuje tylko milisekundy! ) z dostosowywaną precyzją.Jednym z najczęstszych błędów podczas używania sterowników JDBC w odniesieniu do tych trzech typów jest nieprawidłowe obsługiwanie typów. Oznacza to, że sql.Date
jest specyficzna dla strefy czasowej,sql.Time
zawiera bieżący rok, miesiąc i dzień i tak dalej.
Zależy to od typu SQL pola. PreparedStatement
ma elementy ustawiające dla wszystkich trzech wartości, #setDate()
będące wartościami dla sql.Date
, #setTime()
dla sql.Time
i #setTimestamp()
dla sql.Timestamp
.
Pamiętaj, że jeśli używasz ps.setObject(fieldIndex, utilDateObject);
, możesz dać normalneutil.Date
większości sterowników JDBC, które chętnie pożrą je tak, jakby były poprawnego typu, ale kiedy poprosisz o dane później, możesz zauważyć, że w rzeczywistości brakuje ci rzeczy.
To, co mówię, zapisuje milisekundy / nanosekundy jako zwykłe długości i konwertuje je na dowolne obiekty, których używasz ( obowiązkowa wtyczka czasu Joda ). Jednym z hackerskich sposobów, które można zrobić, jest przechowywanie komponentu daty jako jednego komponentu długiego i czasowego jako innego, na przykład teraz będzie to 20100221 i 154536123. Te magiczne liczby mogą być używane w zapytaniach SQL i będą przenośne z bazy danych na inną i pozwoli ci całkowicie ominąć tę część JDBC / Java Date API: s.
PÓŹNA EDYCJA: Począwszy od Java 8 nie powinieneś używać ani,
java.util.Date
ani wjava.sql.Date
ogóle możesz tego uniknąć, a zamiast tego wolisz używaćjava.time
pakietu (opartego na Jodzie) niż czegokolwiek innego. Jeśli nie korzystasz z języka Java 8, oto oryginalna odpowiedź:java.sql.Date
- gdy wywołujesz metody / konstruktory bibliotek, które go używają (jak JDBC). Nie inaczej Nie chcesz wprowadzać zależności do bibliotek baz danych dla aplikacji / modułów, które nie dotyczą jawnie JDBC.java.util.Date
- podczas korzystania z bibliotek, które go używają. W przeciwnym razie, jak najmniej, z kilku powodów:Można go modyfikować, co oznacza, że musisz wykonać jego obronną kopię za każdym razem, gdy go przekażesz lub zwrócisz z metody.
Nie radzi sobie zbyt dobrze z datami, co zdaniem zacofanych ludzi, takich jak twoja, powinny być obsługiwane przez klasy zajmujące się datowaniem.
Ponieważ juD nie radzi sobie zbyt dobrze, wprowadzono upiorne
Calendar
klasy. Są również zmienne i okropne w pracy i należy ich unikać, jeśli nie masz wyboru.Istnieją lepsze alternatywy, takie jak Joda Time API (
który może nawet przekształcić się w Javę 7 i stać się nowym oficjalnym API do obsługi dat- szybkie wyszukiwanie mówi, że nie będzie).Jeśli uważasz, że wprowadzanie nowej zależności, takiej jak Joda,
long
jest przesadą, nie jest wcale tak źle używać pól znaczników czasu w obiektach, chociaż ja zwykle owijam je w JuD podczas ich przekazywania, dla bezpieczeństwa typu i dokumentacji.źródło
java.sql.Date
zPreparedStatement
etc! Ale kiedy go przekazujesz, użyj narzędzia,LocalDate
które konwertujesz za pomocąjava.sql.Date.valueOf
ijava.sql.Date.valueOf
podczas jego ustawiania, i przekonwertuj go z powrotem tak wcześnie, jak to możliwe za pomocąjava.sql.Date.toLocalDate
- ponownie, ponieważ chcesz zaangażować java.sql w jak najmniejszym stopniu, a ponieważ jest on zmienny.Jedyny czas na użycie
java.sql.Date
toPreparedStatement.setDate
. W przeciwnym razie użyjjava.util.Date
. Mówi, żeResultSet.getDate
zwraca a,java.sql.Date
ale można ją przypisać bezpośrednio dojava.util.Date
.źródło
java.sql.Date
można przypisać a,java.util.Date
gdy pierwszy rozszerza drugi? Jaki sens starasz się osiągnąć?Miałem ten sam problem, najłatwiejszy sposób na wstawienie bieżącej daty w przygotowanym wyciągu to:
źródło
tl; dr
Nie używaj żadnego.
java.time.Instant
zastępujejava.util.Date
java.time.LocalDate
zastępujejava.sql.Date
Ani
Obie te klasy są okropne, mają wadliwy projekt i wdrożenie. Unikaj jak koronawirus
zarazy.Zamiast tego należy użyć klas java.time zdefiniowanych w JSR 310. Te klasy są wiodącym w branży środowiskiem do pracy z obsługą daty i czasu. Są one w całości zastąpić krwawe straszne klas starszych, takich jak
Date
,Calendar
,SimpleDateFormat
, i takie.java.util.Date
Pierwszy
java.util.Date
ma reprezentować moment w UTC, co oznacza przesunięcie w stosunku do UTC wynoszące zero godzin-minut-sekund.java.time.Instant
Teraz zastąpiony przez
java.time.Instant
.java.time.OffsetDateTime
Instant
to podstawowa klasa elementów java.time . Aby uzyskać większą elastyczność, użyjOffsetDateTime
zestawu doZoneOffset.UTC
tego samego celu: reprezentowania chwili w UTC.Możesz wysłać ten obiekt do bazy danych przy użyciu
PreparedStatement::setObject
z JDBC 4.2 lub nowszej.Odzyskać.
java.sql.Date
java.sql.Date
Klasa jest straszny i przestarzałe.Ta klasa ma reprezentować tylko datę, bez pory dnia i bez strefy czasowej. Niestety, w wyniku strasznego włamania do projektu klasa ta dziedziczy
java.util.Date
po chwili (data z porą dnia w UTC). Tak więc ta klasa udaje, że jest tylko datą, a jednocześnie ma ukrytą porę dnia i ukryte przesunięcie UTC. To powoduje tyle zamieszania. Nigdy nie używaj tej klasy.java.time.LocalDate
Zamiast tego użyj
java.time.LocalDate
do śledzenia tylko daty (roku, miesiąca, dnia miesiąca) bez żadnej pory dnia, żadnej strefy czasowej ani przesunięcia.Wyślij do bazy danych.
Odzyskać.
O java.time
Środowisko java.time jest wbudowane w Javę 8 i nowsze wersje . Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak
java.util.Date
,Calendar
, iSimpleDateFormat
.Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj stos przepełnienia dla wielu przykładów i wyjaśnień. Specyfikacja to JSR 310 .
Projekt Joda-Time , teraz w trybie konserwacji , zaleca migrację do klas java.time .
Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie potrzeba ciągów, nie ma potrzeby
java.sql.*
klas.Gdzie można uzyskać klasy java.time?
źródło
Klasa java.util.Date w Javie reprezentuje konkretny moment w czasie (np. 25 listopada 2013 16:30:45 do milisekund), ale typ danych DATE w DB reprezentuje tylko datę (np. 25 listopada 2013). Aby zapobiec przypadkowemu dostarczeniu obiektu java.util.Date do bazy danych przez pomyłkę, Java nie pozwala na bezpośrednie ustawienie parametru SQL na java.util.Date:
Ale nadal pozwala ci to robić siłą / intencją (wtedy godziny i minuty będą ignorowane przez sterownik DB). Odbywa się to za pomocą klasy java.sql.Date:
Obiekt java.sql.Date może przechowywać moment w czasie (dzięki czemu można go łatwo zbudować z java.util.Date), ale zgłasza wyjątek, jeśli spróbujesz zapytać go o godziny (w celu wymuszenia jego koncepcji bycia tylko data). Oczekuje się, że sterownik DB rozpozna tę klasę i użyje 0 dla godzin. Spróbuj tego:
źródło
java.util.Date
reprezentuje określony moment w czasie z precyzją milisekundową. Reprezentuje zarówno datę, jak i godzinę bez strefy czasowej. Klasa java.util.Date implementuje interfejs Serializable, Cloneable i Comparable. Jest dziedziczona przezjava.sql.Date
,java.sql.Time
ijava.sql.Timestamp
interfejsów.java.sql.Date
rozszerza klasę java.util.Date, która reprezentuje datę bez informacji o czasie i powinna być używana tylko w przypadku baz danych. Aby zachować zgodność z definicją SQL DATE, wartości milisekund owinięte przezjava.sql.Date
instancję należy „znormalizować”, ustawiając godziny, minuty, sekundy i milisekundy na zero w konkretnej strefie czasowej, z którą instancja jest powiązana.Dziedziczy wszystkie metody publiczne
java.util.Date
, takie jakgetHours()
,getMinutes()
,getSeconds()
,setHours()
,setMinutes()
,setSeconds()
. Ponieważjava.sql.Date
nie przechowuje informacji o czasie, zastępuje wszystkie operacje czasowejava.util.Date
i wszystkie te metody wyrzucają,java.lang.IllegalArgumentException
jeśli są wywoływane, jak wynika to ze szczegółów ich implementacji.źródło