为什么 Oracle 对补充 unicode 字符花栗鼠使用与 java 不同的字节长度?

agr*_*adl 9 oracle java utf-8 unicode

我有 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();
}
Run Code Online (Sandbox Code Playgroud)

这在测试的最后一行失败,并显示以下消息:

ORA-12899: 列
"MYSCHEMA"."TEMP"."FOO" 的值太大(实际:9,最大值:7)

的设置NLS_LENGTH_SEMANTICSBYTE。不幸的是,我无法改变它,因为它是一个遗留系统。我对增加列大小不感兴趣,只是能够可靠地预测字符串的 Oracle 大小。

agr*_*adl 2

问题在于 Oracle 在NLS_LENGTH_SEMANTICSis时处理补充 unicode 字符UTF8

来自文档(添加了重点)。

UTF8 字符集以一个、两个或三个字节对字符进行编码。它适用于基于 ASCII 的平台。

插入到 UTF8 数据库中的增补字符不会损坏数据库中的数据。增补字符被视为两个单独的、用户定义的字符,占用 6 个字节。Oracle 建议您切换到 AL32UTF8,以完全支持数据库字符集中的增补字符。

此外,松鼠字符串中的最后一个代码点是一个变体选择器并且是可选的。我使用unicode 字符检查器看到了这个

更改数据库NLS_CHARACTERSET参数后AL32UTF8测试通过。