2013-07-10 12 views
7

Przeprowadziliśmy migrację z wersji ojdbc6-11.2.0.3.0 do ojdbc7-12.1.0.1 i zaobserwowaliśmy zmianę w semantyce ResultSet#getDate(). Poprzednio zwrócony java.sql.Date byłby "znormalizowany" poprzez ustawienie godzin, minut, sekund i milisekund na zero zgodnie z umową określoną na java.sql.Date. W przypadku ojdbc7 to już nie ma miejsca i java.sql.Date ma ustawione godziny, minuty, sekundy i milisekundy zgodnie z wartością w bazie danych.Zestaw wyników # getDate() semantyka

Spojrzałem na Javadoc z ResultSet#getDate() i nie jest jednoznacznie powiedzieć, które z zachowań jest poprawne. Zakładam, że stare zachowanie było zgodne z zamierzeniami specyfikacji. Czy mam rację? Czy napotkaliśmy błąd sterownika?

+1

Innym problemem, który pojawił się związany ojdbc7-12.1.0.1: PreparedStatement.setDate (indeks java.sql.Date) nie jest skracanie czasu zanim jakikolwiek składnik przechowywania wartości w bazie danych. Może występować tylko z 10g (nie mam 11g lub 12c, aby przetestować go w innych wersjach). –

Odpowiedz

10

Jest to oczywiście błąd w dokumentacji klasy java.sql.Date stany

Aby zachować zgodność z definicją DATA SQL, wartości milisekunda owinięte instancji java.sql.Date musi być „znormalizowane” przez ustawianie godzin, minut, sekund i milisekund na zero w określonej strefie czasowej, z którą powiązana jest instancja.

6

Oracle nie zmienia specyfikacji JDBC. Zaktualizowaliśmy dokumentację sterownika JDBC bazy danych Oracle. Jeśli w dokumentach jest coś, co jest mylące lub niepoprawne, naprawimy to. Jednak nie ma zmiany w specyfikacji JDBC.

Wcześniejsze wersje sterowników są niespójne. W niektórych miejscach zerowali sekundy. W innych miejscach nie. W 12.1 sprawiliśmy, że kierowcy są konsekwentni. Pytanie brzmiało, jakie było właściwe zachowanie. Tak czy inaczej, niektórzy klienci zauważą zmianę w zachowaniu.

Po długim i intensywnym dyskusji zdecydowaliśmy, że najlepszym rozwiązaniem dla klientów Oracle Database nie było zero sekund. Pozwól mi wyjaśnić.

  • Typ DATE ANSI ANSI nie przechowuje sekund. Specyfikacja JDBC zakłada przeważnie ANSI SQL.
  • Typ bazy DATA bazy danych Oracle przechowuje sekundy. Członkowie komisji ANSI SQL zapewnili mnie, że jest to w pełni zgodne z ANSI SQL.
  • Celem JDBC jest udostępnienie bazy danych. Specyfikacja JDBC nie definiuje abstrakcyjnej bazy danych z intencją, że sterowniki implementują tę abstrakcyjną bazę danych. Sterowniki JDBC są wymagane, aby ujawnić szczegóły bazy danych, a nie ukrywać ich. JDBC definiuje narzędzia do abstrakcji niektórych szczegółów bazy danych, ale programista ma wybór, czy użyć tych narzędzi, czy nie.
  • java.sql.Date nie wymusza zachowanie zero sekund choć łatwo mógł. Obowiązek jest wymuszony egzekwowaniem tego zachowania.

Tak więc Oracle DATE ma kilka sekund. Sterownik JDBC Oracle udostępnia bazę danych Oracle. Jeśli getDate zera w sekundach, to straciłoby dane. Dla niektórych użytkowników nie miało to znaczenia, ale dla innych byłoby. Ponieważ Oracle DATE przechowuje sekundy czasu przechowywania wielu baz danych Oracle z drugą dokładnością w kolumnach DATE. Zerowanie sekund w tych przypadkach spowoduje utratę informacji.

Jeśli program przekaże datę o niezerowych sekundach do setDate, program utworzy datę niezgodności. Jeśli sterownik zeruje sekundy, sterownik wyrzucił informacje dostarczone przez program i przechowywane w bazie danych. Ponownie sterownik stracił informacje.

To proste wystarczy napisać SQL lub Java, aby wyzerować sekundy zarówno get i set. Trudniej jest obejść utratę informacji, choć oczywiście jest to możliwe.

Więc zdecydowaliśmy, aby kierowcy konsekwentnie trzymać sekundy na java.sql.Date s. ResultSet.getDate może zbudować java.sql.Date z niezerowymi sekundami, jednak to dokładnie odzwierciedla to, co jest w bazie danych. Jak już wcześniej wspomniano, implementacja Data mogła to wymusić, ale tego nie zrobiła. Jednym ze sposobów obejrzenia tego jest to, że program utworzył datę, kiedy zapisał ją w bazie danych, więc jest to odpowiedzialność programu. Sterownik używa właśnie danych dostarczonych przez program.

Naprawdę mi przykro sterowniki były niespójne wcześniej. Cały czas staramy się usuwać niespójności i dziwne przypadki narożne. Ale mamy ogromną bazę zainstalowaną. Za każdym razem, gdy coś zmieniamy, nawet oczywiste poprawki błędów, wpływ ma jakiś klient. Staramy się znaleźć równowagę między ulepszaniem sterowników i zachowaniem kompatybilności wstecznej. 12c to główne wydanie. Wykorzystaliśmy tę okazję, aby wprowadzić bardziej widoczne zmiany. Przykro nam z powodu zakłóceń, ale uważamy, że jest to właściwe rozwiązanie dla klientów.

+0

Dzięki za wyjaśnienie. –

+4

Specyfikacja jdbc mówi, że java.sql.Date nie ma składnika czasu (w przeciwieństwie do pliku java.sql.Timestamp). Składnik czasu nie ma sensu w wielu kontekstach biznesowych (np. Data urodzenia), a ta zmiana spowoduje, że istniejące aplikacje używające tego zachowania w kontekście biznesowym będą pękać po migracji do wersji 12c. Jeśli programista wymaga komponentu czasu, specyfikacja jdbc wskazuje, że należy użyć get/setTimestamp() zamiast kolumny DATE zamiast get/setDate(). Wreszcie zaoszczędziłoby czas na zidentyfikowaniu problemu, w którym zmiana została wymieniona w pliku README towarzyszącym sterownikowi. –

+1

Wiem, że ten temat powstał dwa lata temu, ale nadal stanowi dla mnie problem. Czy istnieje sposób "powiedz" ojdbc7, aby zachowywał się jak ojdbc6 w tym punkcie ustawiając parametr JVM? To nie był pierwszy raz, kiedy Oracle złamało dotychczasowy kod mojej firmy, wprowadzając takie zmiany z wersji do wersji (mapDateToTimestamp, J2EE13Compliant ...) – RLM

0

Przeanalizowałem ten problem w bazie danych 11g i mogę potwierdzić zachowanie PreparedStatement.setDate(index, java.sql.Date) wymienione przez użytkownika shonky linux (testowałem ojdbc6-11.2.0.4-g vs. ojdbc7-12.1.0.2).

Choć nowe zachowanie prawdopodobnie nie wyraźnie naruszać specyfikacji JDBC, to na pewno nie jest dobrze pasuje do koncepcji konieczności java.sql.Date, java.sql.Time i java.sql.Timestamp i odpowiednich typów danych Types.DATE, Types.TIME i Types.TIMESTAMP.

Podczas gdy pod względem "mniejszym bólem dla obecnych klientów Oracle" decyzja określona przez Douglasa Surbera może mieć sens, nie wydaje się właściwa z perspektywy JDBC (niezależnej od DBMS).

Powiązane problemy