Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Problem z konwersją Oracle SQL DATE przy użyciu iBATIS przez Java JDBC

Pełne informacje (i są bardziej złożone niż opisane tutaj i mogą zależeć od tego, która konkretna wersja sterowników Oracle jest używana) znajduje się w odpowiedzi Richarda Yee tutaj - [nieaktualny link do Nabble]

Szybkie złapanie, zanim wygaśnie z nabble...

Roger, patrz:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01

W szczególności:Proste typy danych Co się dzieje z DATE i TIMESTAMP? Ta sekcja dotyczy prostych typów danych. :-)

Przed wersją 9.2 sterowniki Oracle JDBC mapowały typ DATE SQL na java.sql.Timestamp. Miało to pewien sens, ponieważ typ Oracle DATE SQL zawiera zarówno informacje o dacie, jak i godzinie, podobnie jak java.sql.Timestamp. Bardziej oczywiste mapowanie do java.sql.Date było nieco problematyczne, ponieważ java.sql.Date nie zawiera informacji o czasie. Zdarzało się również, że RDBMS nie wspierał typu SQL TIMESTAMP, więc nie było problemu z mapowaniem DATE na Timestamp.

W wersji 9.2 dodano obsługę TIMESTAMP do RDBMS. Różnica między DATE i TIMESTAMP polega na tym, że TIMESTAMP zawiera nanosekundy, a DATE nie. Tak więc, począwszy od wersji 9.2, DATE jest mapowana na datę, a TIMESTAMP jest mapowana na sygnaturę czasową. Niestety, jeśli polegałeś na wartościach DATE, aby zawierać informacje o czasie, wystąpił problem.

Istnieje kilka sposobów rozwiązania tego problemu:

Zmień tabele tak, aby używały TIMESTAMP zamiast DATE. Jest to prawdopodobnie rzadko możliwe, ale jest najlepszym rozwiązaniem, gdy tak jest.

Zmień aplikację tak, aby używała defineColumnType do definiowania kolumn jako TIMESTAMP zamiast DATE. Są z tym problemy, ponieważ naprawdę nie chcesz używać defineColumnType, chyba że musisz (zobacz Co to jest defineColumnType i kiedy należy go używać?).

Zmień aplikację tak, aby używała getTimestamp zamiast getObject. Jest to dobre rozwiązanie, jeśli to możliwe, jednak wiele aplikacji zawiera ogólny kod, który opiera się na getObject, więc nie zawsze jest to możliwe.

Ustaw właściwość połączenia V8Compatible. To mówi sterownikom JDBC, aby używały starego mapowania zamiast nowego. Tę flagę można ustawić jako właściwość połączenia lub właściwość systemową. Właściwość połączenia ustawia się, dodając ją do obiektu java.util.Properties przekazanego do DriverManager.getConnection lub OracleDataSource.setConnectionProperties. Ustawiasz właściwość systemową, umieszczając opcję -D w wierszu poleceń java.

java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 rozwiązuje ten problem. Począwszy od tej wersji, sterownik domyślnie mapuje kolumny SQL DATE na java.sql.Timestamp. Nie ma potrzeby ustawiania V8Compatible, aby uzyskać prawidłowe mapowanie. V8Compatible jest mocno przestarzały. W ogóle nie powinieneś go używać. Jeśli ustawisz to na true, nic nie zaszkodzi, ale powinieneś przestać go używać.

Chociaż był rzadko używany w ten sposób, V8Compatible istniał nie po to, aby naprawić problem DATE to Date, ale aby zapewnić kompatybilność z bazami danych 8i. Bazy danych 8i (i starsze) nie obsługują typu TIMESTAMP. Ustawienie V8Compatible nie tylko powodowało mapowanie SQL DATE na znacznik czasu podczas odczytu z bazy danych, ale także powodowało, że wszystkie znaczniki czasu były konwertowane na SQL DATE podczas zapisywania w bazie danych. Ponieważ 8i nie jest obsługiwane, sterowniki JDBC 11.1 nie obsługują tego trybu zgodności. Z tego powodu V8Compatible jest nieobsługiwany.

Jak wspomniano powyżej, sterowniki 11.1 domyślnie konwertują SQL DATE na Timestamp podczas odczytu z bazy danych. To zawsze było właściwe, a zmiana w 9i była błędem. Sterowniki 11.1 powróciły do ​​prawidłowego zachowania. Nawet jeśli nie ustawiłeś V8Compatible w swojej aplikacji, w większości przypadków nie powinieneś widzieć żadnej różnicy w zachowaniu. Możesz zauważyć różnicę, jeśli użyjesz getObject do odczytania kolumny DATE. Wynikiem będzie znacznik czasu, a nie data. Ponieważ Timestamp jest podklasą Date, generalnie nie stanowi to problemu. Możesz zauważyć różnicę, jeśli polegasz na konwersji z DATE na Date, aby skrócić składnik czasu, lub jeśli używasz wartości toString. W przeciwnym razie zmiana powinna być przejrzysta.

Jeśli z jakiegoś powodu Twoja aplikacja jest bardzo wrażliwa na tę zmianę i po prostu musisz mieć zachowanie 9i-10g, możesz ustawić właściwość połączenia. Ustaw mapDateToTimestamp na false, a sterownik powróci do domyślnego zachowania 9i-10g i zmapuje DATE na Date.

Jeśli to możliwe, zmień typ kolumny na TIMESTAMP zamiast DATE.

-Richard

Roger Voss napisał:Wysłałem następujące pytanie/problem dotyczący przepełnienia stosu, więc jeśli ktoś zna rozwiązanie, dobrze byłoby zobaczyć tam odpowiedź:

Problem z konwersją Oracle SQL DATE przy użyciu iBATIS przez Java JDBC

Oto opis problemu:

Obecnie zmagam się z problemem konwersji Oracle sql DATE przy użyciu iBATIS z Javy.

Używam cienkiego sterownika Oracle JDBC ojdbc14 w wersji 10.2.0.4.0. iBATIS w wersji 2.3.2. Java 1.6.0_10-rc2-b32.

Problem dotyczy kolumny typu DATE, która jest zwracana przez ten fragment kodu SQL:

SELECT *FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) zamów według from_date

Wywołanie procedury pakietu zwraca kursor ref, który jest opakowany w TABELĘ, w której można łatwo odczytać zbiór wyników tak, jakby był zapytaniem wybierającym w tabeli.

W PL/SQL Developer jedna z zwracanych kolumn, FROM_DATE, typu SQL DATE, ma dokładność do pory dnia:

Tue Dec 16 23:59:00 PST 2008

Ale kiedy uzyskuję dostęp do tego przez iBATIS i JDBC, wartość zachowuje precyzję tylko do dnia dzisiejszego:

Tue Dec 16 12:00:00 AM PST 2008

Jest to wyraźniejsze, gdy jest wyświetlane w następujący sposób:

Powinno być:1229500740000 milisekund od epokiWtorek, 16 grudnia 2008, 23:59:00 PST

Ale zamiast tego otrzymam to:1229414400000 milisekund od epokiWtorek, 16 grudnia 2008 12:00:00 PST (jako instancja klasy java.sql.Date)

Bez względu na to, co próbuję, nie jestem w stanie ujawnić pełnej precyzji tej kolumny DATE, która ma zostać zwrócona przez Java JDBC i iBATIS.

Z czego mapuje iBATIS jest to:

OD_DATA :2008-12-03 :klasa java.sql.Data

Aktualne mapowanie iBATIS wygląda następująco:

Próbowałem też:

lub

Ale wszystkie próby mapowania dają tę samą skróconą wartość Date. To tak, jakby JDBC już wyrządził szkodę poprzez utratę precyzji danych, zanim iBATIS w ogóle ich dotknął.

Najwyraźniej tracę trochę precyzji danych, przechodząc przez JDBC i iBATIS, co się nie dzieje, gdy pozostaję w PL/SQL Developer i uruchamiam ten sam fragment kodu SQL, co skrypt testowy. Wcale nie do przyjęcia, bardzo frustrujące i ostatecznie bardzo przerażające.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Funkcja RAWTONHEX() w Oracle

  2. Nie można zweryfikować, z opcją walidacji

  3. Jak przekonwertować liczbę na ciąg w Oracle?

  4. ODP.NET Oracle.ManagedDataAcess losowe błędy ORA-12570

  5. Ile indeksów bazy danych to za dużo?