Кодировка Oracle JDBC и ограничение 4000 символов

мы пытаемся сохранить кодированную строку UTF-16 в базу данных Oracle AL32UTF8.

наша программа отлично работает на базе данных, которая использует WE8MSWIN1252 как кодировка. Когда мы пытаемся запустить его в базе данных, которая использует AL32UTF8 он доходит до java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column.

в testcase ниже все работает нормально, пока наши входные данные не становятся слишком длинными.

входная строка может превышать 4000 символов. Мы хотим сохранить как можно больше информации, даже если мы понимаем, что вход придется отключить.

наши таблицы базы данных определяются с помощью CHAR ключевое слово (см. ниже). Мы надеялись, что это позволит нам хранить до 4000 символов любого набора символов. можно ли это сделать? Если да, то как?

мы попытались преобразовать строку в UTF8 С помощью ByteBuffer без успеха. OraclePreparedStatement.setFormOfUse(...) также не помогли нам.

переключение на CLOB - это не вариант. Если строка слишком долго его нужно резать.

это наш код на данный момент:

public static void main(String[] args) throws Exception {
    String ip ="193.53.40.229";
    int port = 1521;
    String sid = "ora11";
    String username = "obasi";
    String password = "********";

    String driver = "oracle.jdbc.driver.OracleDriver";
    String url = "jdbc:oracle:thin:@" + ip + ":" + port + ":" + sid;
    Class.forName(driver);

    String shortData = "";
    String longData = "";
    String data;

    for (int i = 0; i < 5; i++)
        shortData += "é";

    for (int i = 0; i < 4000; i++)
        longData += "é";

    Connection conn = DriverManager.getConnection(url, username, password);

    PreparedStatement stat = null;
    try  {
        stat = conn.prepareStatement("insert into test_table_short values (?)");
        data = shortData.substring(0, Math.min(5, shortData.length()));
        stat.setString(1, data);
        stat.execute();

        stat = conn.prepareStatement("insert into test_table_long values (?)");
        data = longData.substring(0, Math.min(4000, longData.length()));
        stat.setString(1, data);
        stat.execute();
    } finally {
        try {
            stat.close();
        } catch (Exception ex){}
    }
}

это сценарий создания простой таблицы:

CREATE TABLE test_table_short (
    DATA    VARCHAR2(5 CHAR);
);

CREATE TABLE test_table_long (
    DATA    VARCHAR2(4000 CHAR);
);

тестовый пример отлично работает на коротких данных. Однако на длинных данных все ошибки. Даже когда наши longData имеет длину всего 3000 символов, он по-прежнему не выполняется успешно.

спасибо заранее!

2 ответов


до Oracle 12.1, a VARCHAR2 столбец ограничен хранением 4000 байтов данных в наборе символов базы данных, даже если он объявлен VARCHAR2(4000 CHAR). Поскольку каждый символ в вашей строке требует 2 байта хранения в наборе символов UTF-8, вы не сможете сохранить более 2000 символов в столбце. Конечно, это число изменится, если некоторые из ваших символов на самом деле требуют всего 1 байт памяти или если некоторые из них требуют более 2 байтов памяти. Когда база данных набор символов-Windows-1252, каждый символ в вашей строке требует только одного байта памяти, поэтому вы сможете хранить 4000 символов в столбце.

поскольку у вас есть более длинные строки, можно ли объявить столбец как CLOB, а не VARCHAR2? Это (эффективно) удалит ограничение длины (существует ограничение на размер CLOB это зависит от версии Oracle и размера блока, но это, по крайней мере, в диапазоне нескольких ГБ).

если вы используете Oracle 12.1 или более поздней версии,


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

stat.substring(0, length)

поскольку это создает строку UTF-8, которая может быть в три раза длиннее, чем разрешено.

while (stat.getBytes("UTF8").length > length) {
  stat = stat.substring(0, stat.length()-1);
}

примечание не используйте stat.getBytes (), так как это зависит от файла set.кодировка " и производит либо Windows-1252, либо UTF-8 байт!

Если вы используете Hibernate, вы можете сделать это с помощью org.зимовать.Перехватчик!