2016-05-19 38 views
5

Jednym z zadań OJDBC jest mapowanie typów danych Oracle na typy Java.Dlaczego OJDBC 7 nie mapuje typu danych CHAR na ciąg Java?

Zauważyliśmy jednak, że jeśli podajemy typ danych CHAR, nie jest on mapowany na java.lang.String. Wersje pokazujące to zachowanie to: OJDBC7 v12.1.0.2 i OJDBC6 v12.1.0.1. Starsze wersje rzeczywiście mapowały typ danych CHAR na: java.lang.String.

Po głębszym wykopaniu odkryliśmy, że istnieje klasa: StructMetaData w pakiecie OJDBC oracle.jdbc.driver implementująca typ danych Oracle do odwzorowania typu Java. Jest w nim pewna metoda: "getColumnClassName (int arg0)", na którą warto zwrócić uwagę. Zauważyliśmy, że na OJDBC v7, przypadki odwzorowane na java.lang.String są następujące:

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"; 
    ... 

Jednak w starszych implementacjach OJDBC, wyglądało to tak:

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"; 
    ... 

Istnieje dodatkowy przypadek odwzorowane na java.lang.String w tym ostatnim przypadku mianowicie. 'przypadek 1'. Ten "przypadek 1" nie jest odwzorowany na java.lang.String w pierwszym urywku kodu pokazanym powyżej.

Na patrząc głębiej, to 'case 1' jest mapowany do CHAR w metodzie getColumnTypeName(int arg0) tego samego StructMetaData Klasa:

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"; 
... 

Z tego powodu, jeśli używamy OJDBC 7 lub OJDBC6 v12.1.0.1 i określić CHAR jako typ danych dla kolumny, następujący kod zwróci null na inwokacji do indeksu Ta kolumna jest:

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

Gdybym zastąpić starszą wersję słoika OJDBC (na przykład: 11.2.0.3), następnie ten sam kod zwraca: java.lang.String. Czy jest to błąd, czy został usunięty przez projekt? Czy ktoś wcześniej zmierzył się z tym samym problemem?

+1

Czy sprawdziłeś informacje o wydaniu sterownika? Jeśli uważasz, że to jest złe, otwórz SR ze wsparciem My Oracle. Byłem bardzo zadowolony z oferowanych rozwiązań. –

Odpowiedz

0

Dobry połów ...!

To naprawdę wygląda jak błąd; być może jedynym argumentem przeciwko temu jest to, że byłoby to niesamowicie ogromne przeoczenie przez Oracle.

Pro bug:

  • problemem kompatybilności wstecz.Aktualizacje przez sterownik JDBC będzie zakłócać istniejących aplikacji, które są jawnie zależnych od deklaracji
  • Ta uwaga o JPublisher Data Type and Java-to-Java Type MappingsCHAR opisuje odwzorowanie postaci z 12c

(uwaga pierwszy wiersz, związany z typem CHAR, która mapy do 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 

Przeciwko bug:

  • Fantazyjna hipoteza może argumentować, że Oracle próbuje odrzucić CHAR s z obsługiwanych typów. Rzeczywiście, typ CHAR nie ma żadnej korzyści w porównaniu z VARCHAR2, a kilka wady sprawiają, że nie ma wyboru. W przeszłości bardzo podobał mi się fakt, że "CHAR" komunikuje się z innymi programistami z zamiarem zdefiniowania elementu o wstępnie zdefiniowanej i niezmiennie ustalonej długości, ale nawet go nie wymusza (po prostu podkłada ciąg znaków, jeśli wypełniasz go zbyt krótka wartość). Jeśli są Państwo zainteresowani, w specjalnej książce poświęconej temu tematowi znajduje się sekcja " ". Możesz przeczytać fragment w Ask Tom "Char Vs Varchar" w punkcie, w którym autor przytacza swoją książkę:

faktu, że CHAR/NCHAR jest niczym więcej niż VARCHAR2/NVARCHAR2 w przebraniu czyni mnie o opinię że tak naprawdę istnieją tylko dwa typy łańcuchów znaków, które kiedykolwiek rozważają, mianowicie VARCHAR2 i NVARCHAR2. Nigdy nie znalazłem zastosowania dla typu CHAR w żadnej aplikacji. Ponieważ typ CHAR zawsze jest pusty, powoduje, że wynikowy ciąg na stałą szerokość, odkrywamy szybko, że zużywa on maksymalną ilość pamięci zarówno w segmencie tabeli, jak i w segmentach indeksów. To by było wystarczająco źle, ale jest jeszcze jeden ważny powód, aby unikać typów CHAR/NCHAR: powodują zamieszanie w aplikacjach, które potrzebują odzyskać te informacje (wielu nie może "znaleźć" swoich danych po ich zapisaniu). Powodem tego są zasady porównywania ciągów znaków i ścisłość, z jaką są one wykonywane. ...

[wtedy świetny przykład następuje w tym samym poście; to jest bardzo warte przeczytania]

Fakt, że CHAR nie są dobre, oczywiście nie usprawiedliwia Oracle z łamania istniejących aplikacji bez wyraźnego powiadomienia; więc hipoteza, że ​​to błąd, jest zdecydowanie bardziej sensowna.

Biorąc pod uwagę, że teoretycznie nie miałoby to wad, jako ekstremalne obejście można zmienić wszystkie zaangażowane tabele w celu ponownego zdefiniowania ich typów CHAR jako VARCHAR2 (jeśli masz do tego prawo i jest to wykonalne).