Saya memiliki kode java pemangkasan string UTF-8 dengan ukuran kolom Oracle (11.2.0.4.0) saya yang akhirnya menimbulkan kesalahan karena java dan Oracle melihat string sebagai panjang byte yang berbeda. Saya telah memverifikasi NLS_CHARACTERSET
parameter saya di Oracle adalah 'UTF8'.
Saya menulis tes yang menggambarkan masalah saya di bawah ini menggunakan emoji unicode chipmunk (🐿️)
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();
}
Ini gagal pada baris terakhir tes dengan pesan berikut:
ORA-12899: nilai terlalu besar untuk kolom
"MYSCHEMA". "TEMP". "FOO" (aktual: 9, maksimum: 7)
Pengaturan NLS_LENGTH_SEMANTICS
adalah BYTE
. Sayangnya, saya tidak dapat mengubah ini karena ini adalah sistem warisan. Saya tidak tertarik untuk meningkatkan ukuran kolom, hanya dapat dipercaya mampu memprediksi ukuran string Oracle.
Jawaban:
Berikut ini adalah spekulasi saya.
Java
String
s diwakili secara internal menggunakan UTF-16 encoding . Ketika AndagetBytes("UTF-8")
Java mengkonversi antara dua pengkodean, dan Anda mungkin menggunakan platform Java yang terbaru.Ketika Anda mencoba untuk menyimpan Java
String
dalam database, Oracle juga melakukan konversi antara Java asli UTF-16 dan karakter basis data yang ditentukan olehNLS_CHARACTERSET
.Karakter chipmunk disetujui sebagai bagian dari standar Unicode pada tahun 2014 (sesuai dengan halaman yang Anda tautkan), sementara rilis terbaru Oracle 11g rel.2 diterbitkan pada tahun 2013 .
Orang mungkin berasumsi bahwa Oracle menggunakan algoritma konversi karakter yang berbeda atau usang sehingga representasi byte 🐿️) di server (panjang 9 byte) berbeda dari apa yang
getBytes()
dikembalikan pada klien (7 byte).Saya kira untuk mengatasi masalah ini Anda dapat memutakhirkan server Oracle Anda atau menggunakan UTF-16 sebagai set karakter basis data.
sumber
Masalahnya adalah ketika Oracle menangani karakter unicode tambahan saat
NLS_LENGTH_SEMANTICS
ituUTF8
.Dari dokumentasi (penekanan ditambahkan).
Selain itu, titik kode terakhir dalam string tupai adalah pemilih variasi dan opsional. Saya melihat ini menggunakan inspektur karakter unicode
Setelah mengubah
NLS_CHARACTERSET
parameter database untukAL32UTF8
tes lulus.sumber