sql >> Databasteknik >  >> RDS >> Oracle

Oracle SQL DATE-konverteringsproblem med iBATIS via Java JDBC

Den fullständiga informationen (och den är mer komplex än vad som beskrivs här och kan bero på vilken speciell version av Oracle-drivrutinerna som används) finns i Richard Yees svar här - [nu utgången länk till Nabble]

Snabbt tag innan det går ut från nabble...

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

Specifikt:Enkla datatyper Vad händer med DATUM och TIDSTÄMPEL? Det här avsnittet handlar om enkla datatyper. :-)

Före 9.2 mappade Oracle JDBC-drivrutinerna DATE SQL-typen till java.sql.Timestamp. Detta var en viss mening eftersom Oracle DATE SQL-typen innehåller både datum- och tidsinformation, liksom java.sql.Timestamp. Den mer uppenbara mappningen till java.sql.Date var något problematisk eftersom java.sql.Date inte innehåller tidsinformation. Det var också så att RDBMS inte stödde TIMESTAMP SQL-typen, så det var inga problem med att mappa DATE till Timestamp.

I 9.2 lades TIMESTAMP-stöd till RDBMS. Skillnaden mellan DATE och TIMESTAMP är att TIMESTAMP inkluderar nanosekunder och DATE inte. Så från och med 9.2 mappas DATE till Date och TIMESTAMP mappas till Timestamp. Om du förlitade dig på DATE-värden för att innehålla tidsinformation är det tyvärr ett problem.

Det finns flera sätt att lösa detta problem:

Ändra dina tabeller så att de använder TIMESTAMP istället för DATE. Detta är förmodligen sällan möjligt, men det är den bästa lösningen när det är så.

Ändra din applikation så att den använder defineColumnType för att definiera kolumnerna som TIMESTAMP snarare än DATUM. Det finns problem med detta eftersom du verkligen inte vill använda defineColumnType om du inte måste (se Vad är defineColumnType och när ska jag använda det?).

Ändra ditt program för att använda getTimestamp istället för getObject. Detta är en bra lösning när det är möjligt, men många applikationer innehåller generisk kod som är beroende av getObject, så det är inte alltid möjligt.

Ställ in egenskapen V8Compatible connection. Detta talar om för JDBC-drivrutinerna att använda den gamla mappningen snarare än den nya. Du kan ställa in denna flagga antingen som en anslutningsegenskap eller en systemegenskap. Du ställer in anslutningsegenskapen genom att lägga till den i java.util.Properties-objektet som skickats till DriverManager.getConnection eller till OracleDataSource.setConnectionProperties. Du ställer in systemegenskapen genom att inkludera ett -D-alternativ i din java-kommandorad.

java -Doracle.jdbc.V8Compatible="true" MyAppOracle JDBC 11.1 fixar det här problemet. Från och med den här versionen mappar drivrutinen SQL DATE-kolumner till java.sql.Timestamp som standard. Det finns ingen anledning att ställa in V8Compatible för att få rätt mappning. V8Compatible är starkt föråldrat. Du bör inte använda det alls. Om du ställer in det på sant kommer det inte att skada någonting, men du bör sluta använda det.

Även om det sällan användes på det sättet, existerade V8Compatible inte för att fixa DATE to Date-problemet utan för att stödja kompatibilitet med 8i-databaser. 8i (och äldre) databaser stödde inte typen TIMESTAMP. Inställningen av V8Compatible ledde inte bara till att SQL DATE mappades till Timestamp när den lästes från databasen, det gjorde också att alla Timestamps konverterades till SQL DATE när de skrevs till databasen. Eftersom 8i inte stöds stöder 11.1 JDBC-drivrutinerna inte detta kompatibilitetsläge. Av denna anledning stöds inte V8Compatible.

Som nämnts ovan konverterar 11.1-drivrutinerna som standard SQL DATE till Timestamp vid läsning från databasen. Detta har alltid varit rätt sak att göra och förändringen av 9i var ett misstag. 11.1-förarna har återgått till korrekt beteende. Även om du inte ställt in V8Compatible i din applikation bör du inte se någon skillnad i beteende i de flesta fall. Du kanske märker en skillnad om du använder getObject för att läsa en DATUM-kolumn. Resultatet blir en tidsstämpel snarare än ett datum. Eftersom Timestamp är en underklass till Date är detta i allmänhet inget problem. Där du kanske märker en skillnad är om du förlitade dig på konverteringen från DATE till Date för att trunkera tidskomponenten eller om du gör toString på värdet. Annars bör ändringen vara transparent.

Om din app av någon anledning är mycket känslig för denna förändring och du helt enkelt måste ha 9i-10g-beteendet, finns det en anslutningsegenskap du kan ställa in. Ställ in mapDateToTimestamp på false och föraren kommer att återgå till standardbeteendet för 9i-10g och mappa DATUM till datum.

Om möjligt bör du ändra din kolumntyp till TIMESTAMP istället för DATE.

-Richard

Roger Voss skrev:Jag postade följande fråga/problem om stackoverflow, så om någon vet en lösning skulle det vara bra att se det besvarat där:

Oracle SQL DATE-konverteringsproblem med iBATIS via Java JDBC

Här är problembeskrivningen:

Jag brottas för närvarande med ett Oracle sql DATE-konverteringsproblem med iBATIS från Java.

Jag använder Oracle JDBC thin drivrutin ojdbc14 version 10.2.0.4.0. iBATIS version 2.3.2. Java 1.6.0_10-rc2-b32.

Problemet kretsar kring en kolumn av typen DATE som returneras av det här utdraget av SQL:

VÄLJ *FRÅN TABELL(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) beställ senast från_datum

Paketproceduranropet returnerar en ref-markör som lindas in i en TABELL till där det är lätt att läsa resultatuppsättningen som om det vore en urvalsfråga mot en tabell.

I PL/SQL Developer har en av kolumnerna som returneras, FROM_DATE, av SQL DATE-typ, precision till tid på dygnet:

Tue Dec 16 23:59:00 PST 2008

Men när jag kommer åt detta via iBATIS och JDBC, behåller värdet bara precisionen i dag:

Tue Dec 16 12:00:00 AM PST 2008

Detta är tydligare när det visas så här:

Borde ha varit:1229500740000 millisekunder sedan epokTisdagen den 16 december 2008 23:59:00 PST

Men får det här istället:1229414400000 millisekunder sedan epochTisday, 16 december 2008 12:00:00 AM PST(som instans av klassen java.sql.Date)

Oavsett vad jag försöker, kan jag inte avslöja den fulla precisionen av denna DATE-kolumn som ska returneras via Java JDBC och iBATIS.

Det iBATIS kartlägger från är detta:

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

Den nuvarande iBATIS-mappningen är denna:

Jag har också provat:

eller

Men alla försök till mappningar ger samma trunkerade datumvärde. Det är som om JDBC redan har gjort skadan genom att förlora dataprecision innan iBATIS ens rör det.

Det är klart att jag tappar en del av min dataprecision genom att gå igenom JDBC och iBATIS, vilket inte händer när jag stannar i PL/SQL Developer och kör samma SQL-snutt som ett testskript. Inte acceptabelt alls, väldigt frustrerande och i slutändan väldigt skrämmande.



  1. OFFSET kontra ROW_NUMBER()

  2. Använda isql med en anslutningssträng

  3. Välj värden från XML-fältet i SQL Server 2008

  4. Skapa en tabell i MySQL