Oracle

為什麼 Oracle 對補充 unicode 字元花栗鼠使用與 java 不同的字節長度?

  • May 22, 2017

我有 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_SEMANTICSBYTE。不幸的是,我無法更改它,因為它是一個遺留系統。我對增加列大小不感興趣,只是能夠可靠地預測字元串的 Oracle 大小。

問題在於 Oracle 在NLS_LENGTH_SEMANTICSis時對補充 unicode 字元的處理UTF8

文件(強調添加)。

UTF8 字元集將字元編碼為一個、兩個或三個字節。它適用於基於 ASCII 的平台。

插入 UTF8 數據庫的補充字元不會破壞數據庫中的數據。**補充字元被視為佔用 6 個字節的兩個單獨的使用者定義字元。**Oracle 建議您切換到 AL32UTF8 以完全支持數據庫字元集中的補充字元。

此外,松鼠字元串中的最後一個程式碼點是變體選擇器,並且是可選的。我使用unicode 字元檢查器看到了這一點

將數據庫的NLS_CHARACTERSET參數更改AL32UTF8為測試通過後。

以下是我的推測。

Java使用 UTF-16 編碼String在內部表示。當Java 在兩種編碼之間進行轉換時,您可能使用的是最新的 Java 平台。getBytes("UTF-8")

當您嘗試String在數據庫中儲存 Java 時,Oracle 還會在 Java 原生 UTF-16 和由NLS_CHARACTERSET.

花栗鼠字元在 2014 年被批准為 Unicode 標準的一部分(根據您連結的頁面),而最新版本的 Oracle 11g rel.2於 2013 年發布

有人可能會假設 Oracle 使用了不同或過時的字元轉換算法,因此伺服器上 🐿️) 的字節表示(9 字節長)getBytes()與客戶端返回的(7 字節)不同。

我想要解決這個問題,您可以升級您的 Oracle 伺服器或使用 UTF-16 作為數據庫字元集。

引用自:https://dba.stackexchange.com/questions/173866