sql >> Database >  >> RDS >> Oracle

Oracle SQL DATE-conversieprobleem met iBATIS via Java JDBC

De volledige info (en het is ingewikkelder dan hier beschreven en kan afhangen van welke specifieke versie van de Oracle-stuurprogramma's in gebruik is) staat in Richard Yee's antwoord hier - [nu verlopen link naar Nabble]

Snel grijpen voordat het verloopt van nabble...

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

Specifiek:Eenvoudige gegevenstypen Wat is er aan de hand met DATE en TIMESTAMP? Dit gedeelte gaat over eenvoudige gegevenstypen. :-)

Vóór 9.2 hebben de Oracle JDBC-stuurprogramma's het DATE SQL-type toegewezen aan java.sql.Timestamp. Dit was enigszins logisch omdat het Oracle DATE SQL-type zowel datum- als tijdinformatie bevat, evenals java.sql.Timestamp. De meer voor de hand liggende toewijzing aan java.sql.Date was enigszins problematisch omdat java.sql.Date geen tijdinformatie bevat. Het was ook zo dat het RDBMS het SQL-type TIMESTAMP niet ondersteunde, dus er was geen probleem met het toewijzen van DATE aan Timestamp.

In 9.2 is TIMESTAMP-ondersteuning toegevoegd aan het RDBMS. Het verschil tussen DATE en TIMESTAMP is dat TIMESTAMP nanoseconden bevat en DATE niet. Dus vanaf 9.2 wordt DATE toegewezen aan Datum en wordt TIMESTAMP toegewezen aan Timestamp. Helaas, als u op DATE-waarden vertrouwde om tijdinformatie te bevatten, is er een probleem.

Er zijn verschillende manieren om dit probleem aan te pakken:

Wijzig uw tabellen om TIMESTAMP te gebruiken in plaats van DATE. Dit is waarschijnlijk zelden mogelijk, maar het is de beste oplossing als dat zo is.

Wijzig uw toepassing om definieerColumnType te gebruiken om de kolommen te definiëren als TIMESTAMP in plaats van DATE. Er zijn hier problemen mee omdat je definieerColumnType niet wilt gebruiken, tenzij het moet (zie Wat is definitieColumnType en wanneer moet ik het gebruiken?).

Wijzig uw toepassing om getTimestamp te gebruiken in plaats van getObject. Dit is waar mogelijk een goede oplossing, maar veel toepassingen bevatten generieke code die afhankelijk is van getObject, dus het is niet altijd mogelijk.

Stel de V8Compatible-verbindingseigenschap in. Dit vertelt de JDBC-stuurprogramma's om de oude toewijzing te gebruiken in plaats van de nieuwe. U kunt deze vlag instellen als verbindingseigenschap of systeemeigenschap. U stelt de verbindingseigenschap in door deze toe te voegen aan het java.util.Properties-object dat is doorgegeven aan DriverManager.getConnection of aan OracleDataSource.setConnectionProperties. U stelt de systeemeigenschap in door een -D-optie op te nemen in uw Java-opdrachtregel.

java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 lost dit probleem op. Vanaf deze release wijst het stuurprogramma standaard SQL DATE-kolommen toe aan java.sql.Timestamp. Het is niet nodig om V8Compatible in te stellen om de juiste mapping te krijgen. V8Compatible wordt sterk afgeraden. Je moet het helemaal niet gebruiken. Als je het op true instelt, kan het geen kwaad, maar je moet het niet meer gebruiken.

Hoewel het zelden op die manier werd gebruikt, bestond V8Compatible niet om het DATE to Date-probleem op te lossen, maar om compatibiliteit met 8i-databases te ondersteunen. 8i (en oudere) databases ondersteunden het TIMESTAMP-type niet. Het instellen van V8Compatible zorgde er niet alleen voor dat SQL DATE werd toegewezen aan Timestamp wanneer het uit de database werd gelezen, het zorgde er ook voor dat alle Timestamps werden geconverteerd naar SQL DATE wanneer ze naar de database werden geschreven. Aangezien 8i niet meer wordt ondersteund, ondersteunen de 11.1 JDBC-stuurprogramma's deze compatibiliteitsmodus niet. Om deze reden wordt V8Compatible niet meer ondersteund.

Zoals hierboven vermeld, converteren de 11.1-stuurprogramma's standaard SQL DATE naar Timestamp bij het lezen uit de database. Dit was altijd het juiste om te doen en de verandering in 9i was een vergissing. De 11.1-stuurprogramma's zijn teruggekeerd naar het juiste gedrag. Zelfs als je V8Compatible niet in je applicatie hebt ingesteld, zou je in de meeste gevallen geen verschil in gedrag moeten zien. U merkt mogelijk een verschil als u getObject gebruikt om een ​​DATE-kolom te lezen. Het resultaat is een tijdstempel in plaats van een datum. Aangezien Timestamp een subklasse van Date is, is dit over het algemeen geen probleem. Waar u een verschil zou kunnen merken, is of u vertrouwt op de conversie van DATE naar Datum om de tijdcomponent af te kappen of als u toString op de waarde doet. Anders moet de wijziging transparant zijn.

Als uw app om de een of andere reden erg gevoelig is voor deze wijziging en u gewoon het 9i-10g-gedrag moet hebben, kunt u een verbindingseigenschap instellen. Stel mapDateToTimestamp in op false en de bestuurder keert terug naar het standaard 9i-10g-gedrag en brengt DATE to Date in kaart.

Indien mogelijk moet u uw kolomtype wijzigen in TIMESTAMP in plaats van DATE.

-Richard

Roger Voss schreef:Ik heb de volgende vraag/probleem gepost op stackoverflow, dus als iemand een oplossing weet, zou het goed zijn om het daar beantwoord te zien:

Oracle SQL DATE-conversieprobleem bij gebruik van iBATIS via Java JDBC

Hier is de probleembeschrijving:

Ik worstel momenteel met een Oracle sql DATE-conversieprobleem met iBATIS uit Java.

Ik gebruik de Oracle JDBC thin driver ojdbc14 versie 10.2.0.4.0. iBATIS versie 2.3.2. Java 1.6.0_10-rc2-b32.

Het probleem draait om een ​​kolom van het type DATE die wordt geretourneerd door dit SQL-fragment:

SELECTEER *FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) bestel voor vanaf_datum

De aanroep van de pakketprocedure retourneert een ref-cursor die in een TABLE wordt verpakt, waar de resultatenset vervolgens gemakkelijk kan worden gelezen alsof het een selectiequery tegen een tabel is.

In PL/SQL Developer heeft een van de geretourneerde kolommen, FROM_DATE, van het type SQL DATE, een precisie tot het tijdstip van de dag:

Tue Dec 16 23:59:00 PST 2008

Maar als ik hier toegang toe krijg via iBATIS en JDBC, blijft de waarde tot op de dag van vandaag nauwkeurig:

Tue Dec 16 12:00:00 AM PST 2008

Dit is duidelijker als het als volgt wordt weergegeven:

Zou moeten zijn:1229500740000 milliseconden sinds epochdinsdag 16 december 2008 23:59:00 PST

Maar krijg dit in plaats daarvan:122941440000 milliseconden sinds epochdinsdag 16 december 2008 12:00:00 uur PST (als instantie van klasse java.sql.Date)

Wat ik ook probeer, ik ben niet in staat om de volledige precisie van deze DATE-kolom weer te geven die moet worden geretourneerd via Java JDBC en iBATIS.

Wat iBATIS in kaart brengt, is dit:

FROM_DATE:2008-12-03:class java.sql.Datum

De huidige iBATIS-toewijzing is deze:

Ik heb ook geprobeerd:

of

Maar alle pogingen tot toewijzingen leveren dezelfde afgekapte datumwaarde op. Het is alsof JDBC de schade van het verliezen van gegevensprecisie al heeft aangericht voordat iBATIS het zelfs maar aanraakt.

Het is duidelijk dat ik een deel van mijn gegevensprecisie verlies door door JDBC en iBATIS te gaan, wat niet gebeurt als ik in PL/SQL Developer blijf en hetzelfde SQL-fragment als een testscript uitvoert. Helemaal niet acceptabel, erg frustrerend en uiteindelijk erg eng.



  1. Wat is een één-op-veel-relatie in een database? Een uitleg met voorbeelden

  2. Retourneer alle rijen van een specifieke partitie in SQL Server (T-SQL)

  3. In-memory OLTP-databases en -tabellen maken en openen

  4. UML-notatie