J'ai du code java qui coupe une chaîne UTF-8 à la taille de ma colonne Oracle (11.2.0.4.0), ce qui finit par générer une erreur car java et Oracle voient la chaîne comme des longueurs d'octets différentes. J'ai vérifié que mon NLS_CHARACTERSET
paramètre dans Oracle est 'UTF8'.
J'ai écrit un test qui illustre mon problème ci-dessous en utilisant les 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();
}
Cela échoue sur la dernière ligne du test avec le message suivant:
ORA-12899: valeur trop grande pour la colonne
"MYSCHEMA". "TEMP". "FOO" (réel: 9, maximum: 7)
Le réglage de NLS_LENGTH_SEMANTICS
est BYTE
. Malheureusement, je ne peux pas changer cela car c'est un système hérité. Je ne suis pas intéressé à augmenter la taille de la colonne, mais à pouvoir prédire de manière fiable la taille Oracle d'une chaîne.
Réponses:
Ce qui suit est ma spéculation.
Les Java
String
sont représentés en interne à l'aide du codage UTF-16 . Lorsque vousgetBytes("UTF-8")
convertissez Java entre les deux encodages, et que vous utilisez probablement une plate-forme Java à jour.Lorsque vous essayez de stocker un Java
String
dans la base de données, Oracle effectue également une conversion entre l'UTF-16 natif Java et le jeu de caractères de la base de données, comme déterminé parNLS_CHARACTERSET
.Le caractère tamia a été approuvé dans le cadre de la norme Unicode en 2014 (selon la page que vous avez liée), tandis que la dernière version d'Oracle 11g rel.2 a été publiée en 2013 .
On pourrait supposer qu'Oracle utilise un algorithme de conversion de caractères différent ou obsolète, de sorte que la représentation en octets de 🐿️) sur le serveur (9 octets de long) est différente de celle qui
getBytes()
revient sur le client (7 octets).Je suppose que pour résoudre ce problème, vous pouvez mettre à niveau votre serveur Oracle ou utiliser UTF-16 comme jeu de caractères de base de données.
la source
Le problème est avec la gestion par Oracle des caractères Unicode supplémentaires quand
NLS_LENGTH_SEMANTICS
c'estUTF8
.À partir de la documentation (emphase ajoutée).
En outre, le dernier point de code dans la chaîne d'écureuil est un sélecteur de variation et facultatif. J'ai vu cela en utilisant un inspecteur de caractères Unicode
Après avoir changé le
NLS_CHARACTERSET
paramètre de la base de données enAL32UTF8
test réussi.la source