2016-05-19 18 views
5

Eine der Aufgaben von OJDBC besteht darin, Oracle-Datentypen Java-Typen zuzuordnen.Warum ordnet OJDBC 7 den CHAR-Datentyp einem Java-String zu?

Allerdings haben wir festgestellt, dass, wenn wir einen CHAR Datentyp geben, es nicht auf java.lang.String zugeordnet ist. Die Versionen mit diesem Verhalten sind: OJDBC7 v12.1.0.2 und OJDBC6 v12.1.0.1. Die älteren Versionen haben tatsächlich den CHAR Datentyp zugeordnet: java.lang.String.

Bei genauerem Hinsehen haben wir festgestellt, dass es eine Klasse gibt: StructMetaData innerhalb des oracle.jdbc.driver Pakets von OJDBC, das den Oracle-Datentyp in Java-Typ-Mapping implementiert. Es gibt eine Methode darin: 'getColumnClassName (int arg0)', die Aufmerksamkeit verdient. Wir haben festgestellt, dass für OJDBC v7, die abgebildeten Fälle java.lang.String sind wie folgt:

int arg1 = this.getColumnType(arg0); 
    switch (arg1) { 
    case -104: 
     return "oracle.sql.INTERVALDS"; 
    case -103: 
     return "oracle.sql.INTERVALYM"; 
    case -102: 
     return "oracle.sql.TIMESTAMPLTZ"; 
    case -101: 
     return "oracle.sql.TIMESTAMPTZ"; 
    case -15: 
    case -9: 
    case 12: 
     return "java.lang.String"; 
    ... 

jedoch innerhalb älteren OJDBC Implementierungen, es sah wie folgt aus:

int arg1 = this.getColumnType(arg0); 
    switch (arg1) { 
    case -104: 
     return "oracle.sql.INTERVALDS"; 
    case -103: 
     return "oracle.sql.INTERVALYM"; 
    case -102: 
     return "oracle.sql.TIMESTAMPLTZ"; 
    case -101: 
     return "oracle.sql.TIMESTAMPTZ"; 
    case -15: 
    case -9: 
    case 1: 
    case 12: 
     return "java.lang.String"; 
    ... 

ein zusätzlicher Fall java.lang.String abgebildet ist im letzteren Fall nämlich. 'Fall 1'. Dieser "Fall 1" wird nicht im ersten Codeausschnitt, der oben gezeigt wird, auf java.lang.String abgebildet.

Auf der Suche tiefer, dieser ‚Fall 1‘ zu CHAR im getColumnTypeName(int arg0) Verfahren derselben StructMetaData Klasse zugeordnet:

public String getColumnTypeName(int arg0) throws SQLException { 
    int arg1 = this.getColumnType(arg0); 
    int arg2 = this.getValidColumnIndex(arg0); 
    switch (arg1) { 
    case -104: 
     return "INTERVALDS"; 
    case -103: 
     return "INTERVALYM"; 
    case -102: 
     return "TIMESTAMP WITH LOCAL TIME ZONE"; 
    case -101: 
     return "TIMESTAMP WITH TIME ZONE"; 
    case -15: 
     return "NCHAR"; 
    case -13: 
     return "BFILE"; 
    case -9: 
     return "NVARCHAR"; 
    case -2: 
     return "RAW"; 
    case 1: 
     return "CHAR"; 
... 

Aus diesem Grund, wenn wir benutzen OJDBC 7 oder OJDBC6 v12.1.0.1 und geben Sie CHAR als Datentyp für eine Spalte, die folgende Code gibt null beim Aufruf für diesen Spalt Index:

for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { 
    ... 
    resultSetMetaData.getColumnClassName(columnIndex) 
    ... 

Wenn ich ersetzen eine ältere Version des OJDBC jar (zum Beispiel: 11.2.0.3), dann gibt derselbe Code zurück: java.lang.String. Ist das ein Fehler oder wurde es vom Design entfernt? Hat jemand schon einmal mit dem gleichen Problem konfrontiert?

+1

Haben Sie die Versionshinweise des Treibers überprüft? Wenn Sie dies für falsch halten, öffnen Sie eine SR mit My Oracle Support. Ich war sehr zufrieden mit den angebotenen Lösungen. –

Antwort

0

Guter Fang ...!

Es sieht wirklich wie ein Fehler aus; Vielleicht ist das einzige Argument dagegen, dass es ein unglaublich großer Überhang von Oracle wäre.

Pro Fehler:

  • Rückwärtskompatibilität Problem.Updates des JDBC-Treibers würde bestehende Anwendungen stören, die auf der CHAR Erklärung ausdrücklich angewiesen sind
  • Diese Notiz JPublisher Data Type and Java-to-Java Type Mappings beschreibt die Abbildung als von 12c

(beachten Sie die erste Zeile, auf die CHAR Art zusammen, die Karten java.lang.String)

| SQL and PL/SQL Data Type | Oracle Mapping | JDBC Mapping 
|------------------------- |------------------|----------------------------------------------- 
| CHAR, CHARACTER, LONG, |     | 
|STRING, VARCHAR, VARCHAR2 | oracle.sql.CHAR | java.lang.String 
| NCHAR, NVARCHAR2   | oracle.sql.NCHAR | oracle.sql.NString 
| NCLOB     | oracle.sql.NCLOB | oracle.sql.NCLOB 

gegen Fehler:

  • Eine ausgefallene Hypothese könnte argumentieren, dass Oracle versucht, CHAR s von den unterstützten Typen zu verwerfen. In der Tat hat der CHAR Typ wirklich keinen Vorteil gegenüber dem VARCHAR2, und ein paar Nachteile machen es zu einer No-Choice. In der Vergangenheit liebte ich die Tatsache, dass ein "CHAR" anderen Entwicklern die Absicht mitteilt, ein Element mit einer vordefinierten und unveränderlich festen Länge zu definieren, aber es erzwingt dies nicht einmal (es füllt nur die Zeichenfolge auf, wenn Sie sie füllen zu einem kurzen Wert). Wenn Sie interessiert sind, gibt es einen Abschnitt in dem ausgezeichneten Buch Expert Oracle Database Architecture - Oracle Database 9i, 10g, and | Thomas Kyte | Apress zum Thema gewidmet. Sie können einen Ausschnitt in Ask Tom "Char Vs Varchar", an der Stelle lesen, wo der Autor sein eigenes Buch zitiert:

Die Tatsache, dass ein CHAR/NCHAR wirklich nichts mehr als ein VARCHAR2/NVARCHAR2 ist in der Verkleidung mich der Meinung macht dass es wirklich nur zwei Zeichenkettentypen gibt, die in Betracht gezogen werden, nämlich VARCHAR2 und NVARCHAR2. Ich habe nie eine Verwendung für den CHAR-Typ in irgendeiner Anwendung gefunden. Da ein CHAR-Typ immer leer den resultierenden String auf eine feste Breite ausblendet, entdecken wir schnell, dass er sowohl im Tabellensegment als auch in allen Indexsegmenten maximalen Speicherplatz verbraucht. Das wäre schlimm genug, aber es gibt noch einen anderen wichtigen Grund, CHAR/NCHAR-Typen zu vermeiden: Sie erzeugen Verwirrung in Anwendungen, die diese Informationen abrufen müssen (viele können ihre Daten nach dem Speichern nicht "finden"). Der Grund dafür bezieht sich auf die Regeln des Zeichenkettenvergleichs und die Strenge, mit der sie ausgeführt werden. ....

[dann ein großartiges Beispiel folgt in der gleichen Post; es ist sehr lesenswert]

Die Tatsache, dass CHAR nicht gut sind, rechtfertigt natürlich nicht, dass Oracle bestehende Anwendungen ohne klare Ankündigung bricht; Die Hypothese, dass es sich um einen Fehler handelt, ist also deutlich vernünftiger.

Da es theoretisch keine Nachteile hätte, könnten Sie als extremes Workaround alle beteiligten Tabellen ändern, um ihre CHAR-Typen als VARCHAR2 neu zu definieren (wenn Sie dazu berechtigt sind und es machbar ist).