Проблемы с кодировкой в ​​ojdbc7/ojdbc8 по сравнению с правильным поведением в ojdbc6

У нас есть база данных Oracle со следующими настройками кодировки

Параметр SELECT, значение FROM nls_database_parameters WHERE параметр, например "NLS%CHARACTERSET"

NLS_NCHAR_CHARACTERSET: AL16UTF16
NLS_CHARACTERSET: WE8ISO8859P15

В этой базе данных у нас есть таблица с полем CLOB, в которой есть запись, начинающаяся со следующей строки, хранящаяся, очевидно, в ISO-8859-15: X²ARB (здесь правильно преобразовано в юникод, в частности, что 2-верхний индекс важен и правилен ).

Затем у нас есть следующий тривиальный фрагмент кода для получения значения, которое должно автоматически преобразовывать кодировку в юникод через поддержку глобализации в Oracle:

private static final String STATEMENT = "SELECT data FROM datatable d WHERE d.id=2562456";

public static void main(String[] args) throws Exception {
    Class.forName("oracle.jdbc.driver.OracleDriver");
    try (Connection conn = DriverManager.getConnection(DB_URL);
         ResultSet rs = conn.createStatement().executeQuery(STATEMENT))
    {
        if (rs.next()) {
            System.out.println(rs.getString(1).substring(0, 5));
        }
    }
}

Запуск кода печатает:

  • с ojdbc8.jar и orai18n.jar: X�ARB -- неверно
  • с ojdbc7.jar и orai18n.jar: X�ARB -- неверно
  • с ojdbc-6.jar: X²ARB -- правильно

Используя UNISTR и изменив оператор на SELECT UNISTR(data) FROM datatable d WHERE d.id=2562456, я могу заставить ojdbc7.jar и ojdbc8.jar возвращать правильное значение, но это потребует неизвестного количества изменений в коде, поскольку это, вероятно, не единственное место, где возникает проблема.

Можно ли что-нибудь сделать с конфигурацией клиента или сервера, чтобы все запросы возвращали правильно закодированные значения без изменений оператора?


person Oleg Sklyar    schedule 19.03.2018    source источник
comment
Вопросы. Возникает ли эта проблема, если тип столбца — VARCHAR2 (вместо CLOB)? Была ли обновлена ​​эта база данных или изменен ее набор символов? Наконец, orai18n.jar не имеет к этому никакого отношения. Это должно нормально работать без orai18n.jar.   -  person Jean de Lavarene    schedule 21.03.2018
comment
Нет, похоже, это специфично для CLOB. Более того, один из коллег только что обнаружил, что с недавно загруженным jodbc6.jr из линейки драйверов 12.1 его поведение похоже на поведение 7 и 8. Очевидно, мы получаем правильное поведение только с jodbc-6.jar, которое у нас было. в течение многих лет с более ранними выпусками нашего продукта. Таким образом, должно было быть изменение, затрагивающее 6 аналогично 7 и 8 :(   -  person Oleg Sklyar    schedule 21.03.2018
comment
Это определенно похоже на ошибку в тонком драйвере JDBC (я предполагаю, что вы используете тонкий). Это может быть связано с предварительной выборкой LOB, когда длина CLOB, идентификатор набора символов и первая часть данных LOB отправляются внутриполосно. Эта функция была представлена ​​в версии 11.2. Можете ли вы попытаться отключить предварительную выборку больших объектов, установив для свойства соединения oracle.jdbc.defaultLobPrefetchSize значение -1?   -  person Jean de Lavarene    schedule 21.03.2018
comment
@JeandeLavarene Это сработало. Пожалуйста, опубликуйте это как ответ, и я с радостью приму его!   -  person Oleg Sklyar    schedule 21.03.2018


Ответы (2)


Это определенно похоже на ошибку в тонком драйвере JDBC (я предполагаю, что вы используете тонкий). Это может быть связано с предварительной выборкой LOB, когда длина CLOB, идентификатор набора символов и первая часть данных LOB отправляются внутриполосно. Эта функция была представлена ​​в версии 11.2. В качестве обходного пути вы можете отключить предварительную выборку больших объектов, установив свойство подключения

oracle.jdbc.defaultLobPrefetchSize

до "-1". Тем временем я буду следить за этой ошибкой, чтобы убедиться, что она будет исправлена.

person Jean de Lavarene    schedule 21.03.2018

Ознакомьтесь с Руководством разработчика базы данных JDBC — Поддержка глобализации

Базовый файл архива Java (JAR) ojdbc7.jar содержит все необходимые классы для обеспечения полной поддержки глобализации для:

  • CHAR или VARCHAR элементы данных объекта и коллекции для наборов символов US7ASCII, WE8DEC, WE8ISO8859P1, WE8MSWIN1252 и UTF8.

Чтобы использовать любые другие наборы символов в элементах данных CHAR или VARCHAR объектов или коллекций, вы должны включить orai18n.jar в переменную среды CLASSPATH:

ORACLE_HOME/jlib/orai18n.jar

person Wernfried Domscheit    schedule 20.03.2018
comment
Мы читаем этот раздел 10 раз, прежде чем опубликовать этот вопрос. Как я указал в вопросе, orai18n.jar находится в пути к классам. - person Oleg Sklyar; 20.03.2018
comment
Я думаю, заявление от Oracle вполне понятно: ojdbc7.jar (и, скорее всего, также ojdbc8.jar) не поддерживает WE8ISO8859P15, т.е. они поддерживают только US7ASCII, WE8DEC, WE8ISO8859P1, WE8MSWIN1252 и UTF8. Другим решением может быть изменение набора символов вашей базы данных, см. Набор символов Миграция - person Wernfried Domscheit; 20.03.2018
comment
Именно по этой причине мы делаем включение orai18n.jar в путь к классам. Так что действительно совершенно неясно, что вы предлагаете (за исключением изменения кодировки БД, что не обязательно является хорошим вариантом). - person Oleg Sklyar; 20.03.2018