為什麼 Oracle 對補充 unicode 字元花栗鼠使用與 java 不同的字節長度?
我有 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 在
NLS_LENGTH_SEMANTICS
is時對補充 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 作為數據庫字元集。