web-dev-qa-db-fra.com

"Valeur de chaîne incorrecte" lors de la tentative d'insertion de UTF-8 dans MySQL via JDBC?

Voici comment ma connexion est établie:
Connection conn = DriverManager.getConnection(url + dbName + "?useUnicode=true&characterEncoding=utf-8", userName, password);

Et j'obtiens l'erreur suivante lorsque je tente d'ajouter une ligne à une table:
Incorrect string value: '\xF0\x90\x8D\x83\xF0\x90...' for column 'content' at row 1

J'insère des milliers d'enregistrements et j'obtiens toujours cette erreur lorsque le texte contient\xF0 (c'est-à-dire que la valeur de chaîne incorrecte commence toujours par\xF0).

Le classement de la colonne est utf8_general_ci.

Quel pourrait être le problème?

185
Lior

Le _utf8_ de MySQL n'autorise que les caractères Unicode pouvant être représentés avec 3 octets en UTF-8. Ici, vous avez un caractère qui nécessite 4 octets:\xF0\x90\x8D\x83 ( + 10343 LETTRE GOTHIC SAUIL ).

Si vous avez MySQL 5.5 ou une version ultérieure, vous pouvez modifier le codage de la colonne de _utf8_ à utf8mb4 . Ce codage permet de stocker des caractères qui occupent 4 octets dans UTF-8.

Vous devrez peut-être également définir la propriété du serveur _character_set_server_ sur _utf8mb4_ dans le fichier de configuration MySQL. Il semble que Connector/J utilise par défaut un format Unicode à 3 octets :

Par exemple, pour utiliser des jeux de caractères UTF-8 sur 4 octets avec Connector/J, configurez le serveur MySQL avec _character_set_server=utf8mb4_ et laissez characterEncoding en dehors de la chaîne de connexion Connector/J. Connector/J détecte ensuite automatiquement le paramètre UTF-8.

274
Joni

Les chaînes contenant \xF0 sont simplement caractères codés sur plusieurs octets utilisant UTF-8.

Bien que votre classement soit défini sur utf8_general_ci, je soupçonne que le codage de caractères de la base de données, de la table ou même de la colonne peut être différent. Ils sont paramètres indépendants . Essayer:

ALTER TABLE database.table MODIFY COLUMN col VARCHAR(255)  
    CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

Remplacez votre type de données actuel par VARCHAR (255)

80
Eric J.

Vous avez le même problème, pour enregistrer les données avec utf8mb4, vous devez vous assurer que:

  1. character_set_client, character_set_connection, character_set_results sont utf8mb4: character_set_client et character_set_connection indiquent le jeu de caractères dans lequel les instructions sont envoyées par le client, character_set_results indique le jeu de caractères dans lequel le serveur renvoie interroger les résultats auprès du client.
    Voir charset-connection .

  2. le codage de table et de colonne est utf8mb4

Pour JDBC, il existe deux solutions:

Solution 1 (besoin de redémarrer MySQL):

  1. modifiez my.cnf comme suit et redémarrez MySQL:

    [mysql]
    default-character-set=utf8mb4
    
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    

cela permet de s'assurer que la base de données et character_set_client, character_set_connection, character_set_results sont utf8mb4 par défaut.

  1. redémarrer MySQL

  2. changez l'encodage de la table et de la colonne en utf8mb4

  3. Arrêtez de spécifier characterEncoding=UTF-8 et characterSetResults=UTF-8 dans le connecteur jdbc, car cela remplacera character_set_client, character_set_connection, character_set_results en utf8

Solution 2 (vous n'avez pas besoin de redémarrer MySQL):

  1. changez l'encodage de la table et de la colonne en utf8mb4

  2. en spécifiant characterEncoding=UTF-8 dans le connecteur jdbc, le connecteur jdbc ne supporte pas utf8mb4.

  3. écrivez votre déclaration SQL comme ceci (vous devez ajouter allowMultiQueries=true au connecteur jdbc):

    'SET NAMES utf8mb4;INSERT INTO Mytable ...';
    

cela permettra de s'assurer que chaque connexion au serveur, character_set_client,character_set_connection,character_set_results est utf8mb4.
Voir aussi charset-connection .

47
madtracy

Je voulais combiner quelques articles pour en donner une réponse complète, car il semble y avoir quelques étapes.

  1. Conseil ci-dessus par @madtracey

/etc/mysql/my.cnf ou /etc/mysql/mysql.conf.d/mysqld.cnf

[mysql]
default-character-set=utf8mb4

[mysqld_safe]
socket          = /var/run/mysqld/mysqld.sock
Nice            = 0

[mysqld]
##
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Encore une fois par conseil, les connexions jdbc avaient characterEncoding=UTF-8et characterSetResults=UTF-8 supprimées

Avec cet ensemble, -Dfile.encoding=UTF-8 semblait ne faire aucune différence.

Je ne pouvais toujours pas écrire de texte international dans la base de données obtenant le même échec que ci-dessus

Maintenant, en utilisant ceci comment-convertir-un-ensemble-mysql-base-caractères-et-collation-en-utf-8

Mettez à jour toute votre base de données pour utiliser utf8mb4

ALTER DATABASE YOURDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Exécutez cette requête qui vous indique ce qui doit être appelé

SELECT CONCAT(
'ALTER TABLE ',  table_name, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;  ', 
'ALTER TABLE ',  table_name, ' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;  ')
FROM information_schema.TABLES AS T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` AS C
WHERE C.collation_name = T.table_collation
AND T.table_schema = 'YOURDB'
AND
(C.CHARACTER_SET_NAME != 'utf8mb4'
    OR
 C.COLLATION_NAME not like 'utf8mb4%')

Copier coller la sortie dans l'éditeur remplace tout | avec rien poster dans mysql lorsqu'il est connecté à corriger db.

C'est tout ce qui devait être fait et tout semble fonctionner pour moi. Pas le -Dfile.encoding=UTF-8 n'est pas activé et il semble fonctionner comme prévu

E2A Vous avez toujours un problème? Je suis certainement en production, il est donc nécessaire de vérifier ce qui a été fait ci-dessus, car cela arrive parfois. ne fonctionne pas, voici la raison et résoudre dans ce scénario:

show create table user

  `password` varchar(255) CHARACTER SET latin1 NOT NULL,
  `username` varchar(255) CHARACTER SET latin1 NOT NULL,

Vous pouvez voir que certains sont toujours en train de tenter de mettre à jour l'enregistrement manuellement:

ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

Alors affinons le:

mysql> ALTER TABLE user change username username varchar(255) CHARACTER SET utf8mb4 not NULL;
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
mysql> ALTER TABLE user change username username varchar(100) CHARACTER SET utf8mb4 not NULL;
Query OK, 5 rows affected (0.01 sec)

En bref, j'ai dû réduire la taille de ce champ pour que la mise à jour fonctionne.

Maintenant quand je cours:

mysql> ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0

Tout fonctionne

10
Vahid

Dans mon cas, j'ai tout essayé ci-dessus, rien n'a fonctionné. Je suis assez sûr, ma base de données ressemble à celle ci-dessous.

mysql  Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using  EditLine wrapper

Connection id:      12
Current database:   xxx
Current user:       yo@localhost
SSL:            Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.17-0ubuntu0.16.04.1 (Ubuntu)
Protocol version:   10
Connection:     Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8
UNIX socket:        /var/run/mysqld/mysqld.sock
Uptime:         42 min 49 sec

Threads: 1  Questions: 372  Slow queries: 0  Opens: 166  Flush tables: 1  Open tables: 30  Queries per second avg: 0.144

alors, je regarde le jeu de caractères de la colonne dans chaque table

show create table company;

Il s'avère que le jeu de caractères de la colonne est latin. C'est pourquoi, je ne peux pas insérer de chinois dans la base de données.

 ALTER TABLE company CONVERT TO CHARACTER SET utf8;

Cela pourrait vous aider. :)

5
crazy_phage

En supposant que vous utilisez phpmyadmin pour résoudre cette erreur, procédez comme suit:

  1. phpMyAdmin
  2. votre_table
  3. "Onglet Structure"
  4. changez le classement de votre champ de latin1_swedish_ci (ou quoi que ce soit) en utf8_general_ci
5
Teo Mihaila

fais juste

ALTER TABLE `some_table` 
CHARACTER SET = utf8 , COLLATE = utf8_general_ci ;

ALTER TABLE `some_table` 
CHANGE COLUMN `description_with_latin_or_something` `description` TEXT CHARACTER SET 'utf8' NOT NULL ;
4
shareef

J'ai eu ce problème avec mon application PLAY Java. Voici ma trace de pile pour cette exception:

javax.persistence.PersistenceException: Error[Incorrect string value: '\xE0\xA6\xAC\xE0\xA6\xBE...' for column 'product_name' at row 1]
  at io.ebean.config.dbplatform.SqlCodeTranslator.translate(SqlCodeTranslator.Java:52)
  at io.ebean.config.dbplatform.DatabasePlatform.translate(DatabasePlatform.Java:192)
  at io.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.Java:83)
  at io.ebeaninternal.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.Java:49)
  at io.ebeaninternal.server.core.PersistRequestBean.executeInsert(PersistRequestBean.Java:1136)
  at io.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.Java:723)
  at io.ebeaninternal.server.core.PersistRequestBean.executeNoBatch(PersistRequestBean.Java:778)
  at io.ebeaninternal.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.Java:769)
  at io.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.Java:456)
  at io.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.Java:406)
  at io.ebeaninternal.server.persist.DefaultPersister.save(DefaultPersister.Java:393)
  at io.ebeaninternal.server.core.DefaultServer.save(DefaultServer.Java:1602)
  at io.ebeaninternal.server.core.DefaultServer.save(DefaultServer.Java:1594)
  at io.ebean.Model.save(Model.Java:190)
  at models.Product.create(Product.Java:147)
  at controllers.PushData.xlsupload(PushData.Java:67)
  at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$40(Routes.scala:690)
  at play.core.routing.HandlerInvokerFactory$$anon$3.resultCall(HandlerInvoker.scala:134)
  at play.core.routing.HandlerInvokerFactory$$anon$3.resultCall(HandlerInvoker.scala:133)
  at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$8$$anon$2$$anon$1.invocation(HandlerInvoker.scala:108)
  at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:88)
  at play.http.DefaultActionCreator$1.call(DefaultActionCreator.Java:31)
  at play.core.j.JavaAction.$anonfun$apply$8(JavaAction.scala:138)
  at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:655)
  at scala.util.Success.$anonfun$map$1(Try.scala:251)
  at scala.util.Success.map(Try.scala:209)
  at scala.concurrent.Future.$anonfun$map$1(Future.scala:289)
  at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
  at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
  at scala.concurrent.impl.CallbackRunnable.run$$$capture(Promise.scala:60)
  at scala.concurrent.impl.CallbackRunnable.run(Promise.scala)
  at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
  at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
  at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:48)
  at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:68)
  at scala.concurrent.impl.Promise$KeptPromise$Kept.onComplete(Promise.scala:368)
  at scala.concurrent.impl.Promise$KeptPromise$Kept.onComplete$(Promise.scala:367)
  at scala.concurrent.impl.Promise$KeptPromise$Successful.onComplete(Promise.scala:375)
  at scala.concurrent.impl.Promise.transform(Promise.scala:29)
  at scala.concurrent.impl.Promise.transform$(Promise.scala:27)
  at scala.concurrent.impl.Promise$KeptPromise$Successful.transform(Promise.scala:375)
  at scala.concurrent.Future.map(Future.scala:289)
  at scala.concurrent.Future.map$(Future.scala:289)
  at scala.concurrent.impl.Promise$KeptPromise$Successful.map(Promise.scala:375)
  at scala.concurrent.Future$.apply(Future.scala:655)
  at play.core.j.JavaAction.apply(JavaAction.scala:138)
  at play.api.mvc.Action.$anonfun$apply$2(Action.scala:96)
  at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:304)
  at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
  at scala.concurrent.impl.CallbackRunnable.run$$$capture(Promise.scala:60)
  at scala.concurrent.impl.CallbackRunnable.run(Promise.scala)
  at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
  at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
  at scala.runtime.Java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.Java:12)
  at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
  at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91)
  at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
  at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
  at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.Java:260)
  at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.Java:1339)
  at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.Java:1979)
  at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.Java:107)
Caused by: Java.sql.SQLException: Incorrect string value: '\xE0\xA6\xAC\xE0\xA6\xBE...' for column 'product_name' at row 1
  at com.mysql.jdbc.SQLError.createSQLException(SQLError.Java:1074)
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.Java:4096)
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.Java:4028)
  at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.Java:2490)
  at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.Java:2651)
  at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.Java:2734)
  at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.Java:2155)
  at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.Java:2458)
  at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.Java:2375)
  at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.Java:2359)
  at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.Java:61)
  at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.Java)
  at io.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.Java:82)
  at io.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.Java:122)
  at io.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.Java:73)
  ... 59 more

J'essayais de sauvegarder un enregistrement en utilisant io.Ebean. Je l'ai corrigé en recréant ma base de données avec le classement utf8mb4 et appliqué play evolution pour recréer toutes les tables de manière à ce que toutes les tables soient recréées avec le classement en utf-8.

CREATE DATABASE inventory CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
3
Md Ashfak Chowdhury

J'ai eu le même problème dans mon Rails projet:

Incorrect string value: '\xF0\xA9\xB8\xBDs ...' for column 'subject' at row1

Solution 1: avant d'enregistrer dans la base de données, convertissez la chaîne en base64 de Base64.encode64(subject) et après l'extraction de la base de données, utilisez Base64.decode64(subject).

Solution 2:

Étape 1: modifiez le jeu de caractères (et le classement) de la colonne sujet par

ALTER TABLE t1 MODIFY
subject VARCHAR(255)
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

Étape 2: Dans database.yml, utilisez

encoding :utf8mb4
3
ravi

C'est principalement dû à certains caractères Unicode. Dans mon cas, c'était le symbole monétaire de la roupie.

Pour résoudre rapidement ce problème, je devais repérer le personnage à l'origine de cette erreur. J'ai copié le texte entier dans un éditeur de texte comme vi et j'ai remplacé le caractère troublant par un texte.

3
BTR Naidu

Si vous ne souhaitez appliquer la modification qu'à un seul champ, vous pouvez essayer de le sérialiser.

class MyModel < ActiveRecord::Base
  serialize :content

  attr_accessible :content, :title
end
2
Paul Marclay

Vous devez définir utf8mb4 en méta html et également dans votre serveur, modifiez tabel et définissez le classement sur utf8mb4.

1
Sona Israyelyan

Si vous créez une nouvelle table MySQL, vous pouvez spécifier le jeu de caractères de toutes les colonnes lors de la création, ce qui a résolu le problème pour moi.

CREATE TABLE tablename (
<list-of-columns>
)
CHARSET SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Vous pouvez lire plus de détails: https://dev.mysql.com/doc/refman/8.0/en/charset-column.html

1
amucunguzi

ma solution est de changer le type de colonne de varchar (255) à blob

1
zhuochen shen

ce n'est pas la solution de recommandation .. Mais vaut la peine de partager. Depuis mon projet, mettez à niveau le SGBD de Mysql ancien vers le plus récent (8). Mais je ne peux pas changer la structure de la table, seulement la configuration du SGBD (mysql). La solution pour le serveur mysql.

test sur Windows mysql 8.0.15 sur mysql config recherche

sql-mode = "....."

décommentez-le. Ou dans mon cas, tapez/ajoutez

sql-mode = "NO_ENGINE_SUBSTITUTION"

pourquoi pas solution recommandée. parce que si vous utilisez latin1 (mon cas) .. les données ont été insérées avec succès mais pas le contenu (mysql ne répond pas avec une erreur !!). par exemple vous tapez info comme ça

bla\x12

ça sauve

bla [] (boîte)

ok .. pour mon problème .. je peux changer le champ en UTF8 .. Mais il y a un petit problème .. voir la réponse ci-dessus à propos d'une autre solution a échoué parce que le mot n'est pas inséré car contient plus de 2 octets (cmiiw) .. this solution pour que vos données d’insertion deviennent une boîte. Le raisonnable est d'utiliser blob .. et vous pouvez ignorer ma réponse.

Un autre test lié à cela était .. en utilisant tf8_encode sur votre code avant de sauvegarder. J'utilise sur latin1 et c'était un succès (je n'utilise pas sql-mode)! Identique à la réponse ci-dessus en utilisant base64_encode.

Ma suggestion pour analyser votre besoin de table et essayé de passer d'un autre format à UTF8

0
user2905554