sql >> Databáze >  >> RDS >> Oracle

Problém převodu Oracle SQL DATE pomocí iBATIS přes Java JDBC

Úplné informace (a jsou složitější, než je zde popsáno a mohou záviset na tom, která konkrétní verze ovladačů Oracle se používá) je v odpovědi Richarda Yee zde - [odkaz na Nabble nyní vypršel]

Rychlé uchopení, než vyprší z nabble...

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

Konkrétně:Jednoduché datové typy Co se děje s DATE a TIMESTAMP? Tato část je o jednoduchých datových typech. :-)

Před verzí 9.2 mapovaly ovladače Oracle JDBC typ DATE SQL na java.sql.Timestamp. To dávalo určitý smysl, protože typ Oracle DATE SQL obsahuje informace o datu i čase, stejně jako java.sql.Timestamp. Zřetelnější mapování na java.sql.Date bylo poněkud problematické, protože java.sql.Date nezahrnuje časové informace. Stalo se také, že RDBMS nepodporovalo typ SQL TIMESTAMP, takže nebyl problém s mapováním DATE na Timestamp.

V 9.2 byla do RDBMS přidána podpora TIMESTAMP. Rozdíl mezi DATE a TIMESTAMP je ten, že TIMESTAMP zahrnuje nanosekundy a DATE nikoli. Takže od 9.2 je DATE mapováno na Date a TIMESTAMP je mapováno na Timestamp. Bohužel, pokud jste se spoléhali na to, že hodnoty DATE obsahují časové informace, nastal problém.

Existuje několik způsobů, jak tento problém vyřešit:

Upravte své tabulky tak, aby místo DATE používali TIMESTAMP. To je pravděpodobně jen zřídka možné, ale pokud ano, je to nejlepší řešení.

Upravte aplikaci tak, aby používala defineColumnType k definování sloupců jako TIMESTAMP, nikoli DATE. S tím jsou problémy, protože opravdu nechcete používat defineColumnType, pokud nemusíte (viz Co je defineColumnType a kdy jej mám použít?).

Změňte svou aplikaci tak, aby používala getTimestamp spíše než getObject. Toto je dobré řešení, pokud je to možné, ale mnoho aplikací obsahuje obecný kód, který se spoléhá na getObject, takže to není vždy možné.

Nastavte vlastnost připojení V8Compatible. To říká ovladačům JDBC, aby použili staré mapování namísto nového. Tento příznak můžete nastavit buď jako vlastnost připojení nebo jako systémovou vlastnost. Vlastnost připojení nastavíte tak, že ji přidáte do objektu java.util.Properties předaného do DriverManager.getConnection nebo do OracleDataSource.setConnectionProperties. Vlastnost systému nastavíte vložením volby -D do příkazového řádku java.

java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 řeší tento problém. Počínaje touto verzí ovladač ve výchozím nastavení mapuje sloupce SQL DATE na java.sql.Timestamp. Pro získání správného mapování není potřeba nastavovat V8Compatible. V8Compatible je silně zastaralá. Neměli byste ho používat vůbec. Pokud to nastavíte na true, nic to nezkazí, ale měli byste to přestat používat.

Ačkoli to bylo zřídka používáno tímto způsobem, V8Compatible existoval ne proto, aby opravoval problém DATE to Date, ale aby podporoval kompatibilitu s databázemi 8i. Databáze 8i (a starší) nepodporovaly typ TIMESTAMP. Nastavení V8Compatible způsobilo nejen mapování data SQL DATE na časové razítko při čtení z databáze, ale také to, že všechna časová razítka byla při zápisu do databáze převedena na datum SQL. Protože 8i není podporováno, ovladače 11.1 JDBC nepodporují tento režim kompatibility. Z tohoto důvodu je V8 Compatible ukončena.

Jak je uvedeno výše, ovladače 11.1 ve výchozím nastavení převádějí SQL DATE na časové razítko při čtení z databáze. Vždy to byla správná věc a změna v 9i byla chyba. Ovladače 11.1 se vrátily ke správnému chování. I když jste ve své aplikaci nenastavili V8Compatible, ve většině případů byste neměli vidět žádný rozdíl v chování. Pokud použijete getObject ke čtení sloupce DATE, můžete si všimnout rozdílu. Výsledkem bude spíše časové razítko než datum. Protože Timestamp je podtřídou Date, není to obecně problém. Rozdíl si můžete všimnout, pokud jste se spoléhali na převod z DATE na datum, abyste zkrátili časovou složku, nebo pokud toString provedete na hodnotě. Jinak by změna měla být transparentní.

Pokud je z nějakého důvodu vaše aplikace na tuto změnu velmi citlivá a vy prostě musíte mít chování 9i-10g, existuje vlastnost připojení, kterou můžete nastavit. Nastavte mapDateToTimestamp na hodnotu false a ovladač se vrátí k výchozímu chování 9i-10g a mapuje DATE na datum.

Pokud je to možné, měli byste změnit typ sloupce na TIMESTAMP namísto DATE.

-Richard

Roger Voss napsal:Zveřejnil jsem následující otázku/problém na stackoverflow, takže pokud někdo zná řešení, bylo by dobré vidět tam odpověď:

Problém převodu Oracle SQL DATE pomocí iBATIS přes Java JDBC

Zde je popis problému:

Momentálně se potýkám s problémem převodu Oracle SQL DATE pomocí iBATIS z Javy.

Používám tenký ovladač Oracle JDBC ojdbc14 verze 10.2.0.4.0. iBATIS verze 2.3.2. Java 1.6.0_10-rc2-b32.

Problém se točí kolem sloupce typu DATE, který vrací tento fragment SQL:

SELECT *FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) objednat do od_datum

Volání procedury balíčku vrací ref kurzor, který je zabalen do TABLE, kde je pak snadné přečíst sadu výsledků, jako by to byl výběrový dotaz proti tabulce.

V PL/SQL Developer má jeden z vrácených sloupců, FROM_DATE, typu SQL DATE, přesnost na denní dobu:

Tue Dec 16 23:59:00 PST 2008

Ale když k tomu přistupuji přes iBATIS a JDBC, hodnota si zachovává přesnost až do dneška:

Tue Dec 16 12:00:00 AM PST 2008

Toto je jasnější, když se zobrazí takto:

Mělo to být:1229500740000 milisekund od epochy úterý 16. prosince 2008 23:59:00 PST

Ale místo toho získáte toto:1229414400000 milisekund od epochúterý, 16. prosince 2008 00:00:00 PST (jako instance třídy java.sql.Date)

Bez ohledu na to, co zkouším, nejsem schopen odhalit plnou přesnost tohoto sloupce DATE, který má být vrácen prostřednictvím Java JDBC a iBATIS.

Z čeho iBATIS mapuje je toto:

FROM_DATE :2008-12-03 :třída java.sql.Date

Aktuální mapování iBATIS je toto:

Zkoušel jsem také:

nebo

Ale všechny pokusy o mapování poskytují stejnou zkrácenou hodnotu Date. Je to, jako by JDBC již napáchalo škodu tím, že ztratilo přesnost dat ještě předtím, než se jí iBATIS vůbec dotkne.

Je zřejmé, že ztrácím část své přesnosti dat tím, že procházím JDBC a iBATIS, což se neděje, když zůstanu v PL/SQL Developer se stejným úryvkem SQL jako testovací skript. Vůbec nepřijatelné, velmi frustrující a nakonec velmi děsivé.



  1. Výhody a nevýhody používání uložených procedur

  2. Co je tento operátor <=> v MySQL?

  3. Získejte hodnotu na základě max. z jiného sloupce seskupeného podle jiného sloupce

  4. Klonování databází pomocí PSDatabaseClone