У меня есть Java-код, обрезающий строку UTF-8 до размера моего столбца Oracle (11.2.0.4.0), который в итоге выдает ошибку, потому что Java и Oracle видят строку как разные длины байтов. Я подтвердил, что мой NLS_CHARACTERSET
параметр в Oracle - «UTF8».
Я написал тест, который иллюстрирует мою проблему ниже, используя эмодзи бурундук Unicode (🐿️)
public void test() throws UnsupportedEncodingException, SQLException {
String squirrel = "\uD83D\uDC3F\uFE0F";
int squirrelByteLength = squirrel.getBytes("UTF-8").length; //this is 7
Connection connection = dataSource.getConnection();
connection.prepareStatement("drop table temp").execute();
connection.prepareStatement("create table temp (foo varchar2(" + String.valueOf(squirrelByteLength) + "))").execute();
PreparedStatement statement = connection.prepareStatement("insert into temp (foo) values (?)");
statement.setString(1, squirrel);
statement.executeUpdate();
}
Это завершается с ошибкой в последней строке теста со следующим сообщением:
ORA-12899: слишком большое значение для столбца
"MYSCHEMA". "TEMP". "FOO" (фактическое: 9, максимальное: 7)
Настройка NLS_LENGTH_SEMANTICS
есть BYTE
. К сожалению, я не могу изменить это, поскольку это устаревшая система. Я не заинтересован в увеличении размера столбца, просто могу надежно предсказать размер строки Oracle в Oracle.
Ответы:
Далее следует мое предположение.
Java
String
с являются внутренне представлены с использованием UTF-16 кодировки . Когда выgetBytes("UTF-8")
преобразовываете Java между двумя кодировками и, вероятно, используете современную платформу Java.Когда вы пытаетесь сохранить Java
String
в базе данных, Oracle также выполняет преобразование между собственным UTF-16 Java и набором символов базы данных, как определеноNLS_CHARACTERSET
.Символ бурундука был утвержден как часть стандарта Unicode в 2014 году (согласно странице, на которую вы ссылаетесь), в то время как последний выпуск Oracle 11g rel.2 был опубликован в 2013 году .
Можно предположить, что Oracle использует другой или устаревший алгоритм преобразования символов, поэтому байтовое представление 🐿️) на сервере (длина 9 байт) отличается от того, что
getBytes()
возвращает клиент (7 байт).Я думаю, что для решения этой проблемы вы можете обновить сервер Oracle или использовать UTF-16 в качестве набора символов базы данных.
источник
Проблема связана с обработкой Oracle дополнительных символов Юникода, когда
NLS_LENGTH_SEMANTICS
естьUTF8
.Из документации (выделение добавлено).
Кроме того, последняя кодовая точка в строке белка является селектором вариантов и является необязательной. Я видел это с помощью инспектора символов Unicode
После изменения базы данных
NLS_CHARACTERSET
параметров дляAL32UTF8
испытания прошли.источник