web-dev-qa-db-ja.com

JDBC経由でMySQLにUTF-8を挿入しようとしたときの「不正な文字列値」

これが私の接続の設定方法です:
Connection conn = DriverManager.getConnection(url + dbName + "?useUnicode=true&characterEncoding=utf-8", userName, password);

テーブルに行を追加しようとすると、次のようなエラーが表示されます。
Incorrect string value: '\xF0\x90\x8D\x83\xF0\x90...' for column 'content' at row 1

何千ものレコードを挿入していますが、テキストに\ xF0が含まれていると常にこのエラーが発生します(つまり、誤った文字列値は常に\ xF0で始まります)。

列の照合はutf8_general_ciです。

問題は何でしょうか。

173
Lior

MySQLのutf8では、UTF-8で3バイトで表現できるUnicode文字のみが許可されています。ここには4バイトが必要な文字があります。\ xF0\x90\x8D\x83( U + 10343ゴシックレターソイル )。

MySQL 5.5以降をお持ちの場合は、カラムエンコーディングをutf8から utf8mb4 に変更できます。このエンコーディングは、UTF-8で4バイトを占める文字の格納を可能にします。

MySQL設定ファイルでサーバープロパティcharacter_set_serverutf8mb4に設定する必要があるかもしれません。それ以外の場合 Connector/Jはデフォルトの3バイトUnicodeになります

たとえば、Connector/Jで4バイトのUTF-8文字セットを使用するには、MySQLサーバをcharacter_set_server=utf8mb4で設定し、characterEncodingをConnector/J接続文字列から除外します。その後、Connector/JはUTF-8設定を自動検出します。

262
Joni

\xF0を含む文字列は、単純に UTF-8を使用した複数バイト としてエンコードされた文字です。

照合順序はutf8_general_ciに設定されていますが、データベース、テーブル、さらには列の文字エンコードが異なる可能性があります。それらは 独立した設定 です。試してください:

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

実際のデータ型がVARCHAR(255)のものであれば何でも代用してください。

78
Eric J.

utf8mb4を使用してデータを保存するには、次の点を確認する必要があります。

  1. character_set_client, character_set_connection, character_set_resultsutf8mb4です。character_set_clientおよびcharacter_set_connectionは、クライアントによってステートメントが送信される文字セットを示し、character_set_resultsは、サーバーがクライアントに照会結果を返すときの文字セットを示します。
    charset-connection を参照してください。

  2. テーブルと列のエンコーディングはutf8mb4です。

JDBCの場合、2つの解決策があります。

解決策1(MySQLを再起動する必要があります):

  1. 次のようにmy.cnfを修正してMySQLを再起動します。

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

これにより、データベースとcharacter_set_client, character_set_connection, character_set_resultsがデフォルトでutf8mb4であることを確認できます。

  1. mySQLを再起動します

  2. テーブルと列のエンコーディングをutf8mb4に変更します

  3. JdbcコネクターでcharacterEncoding=UTF-8およびcharacterSetResults=UTF-8の指定を停止すると、character_set_clientcharacter_set_connectioncharacter_set_resultsutf8にオーバーライドされます。

解決策2(MySQLを再起動する必要はありません)

  1. テーブルと列のエンコーディングをutf8mb4に変更します

  2. jdbcコネクタでcharacterEncoding=UTF-8を指定すると、jdbcコネクタはutf8mb4をサポートしません。

  3. あなたのSQL文を次のように書いてください(jdbcコネクタにallowMultiQueries=trueを追加する必要があります):

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

これにより、サーバーへの各接続character_set_client,character_set_connection,character_set_resultsutf8mb4になります。
charset-connection もご覧ください。

42
madtracy

それは数ステップであるように見えるので、私はこれの完全な答えをするために2、3の投稿を結合したかったです。

  1. @ madtraceyによるアドバイス以上

/etc/mysql/my.cnfまたは/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

やはり上記のアドバイスから、すべてのJDBC接続がcharacterEncoding=UTF-8characterSetResults=UTF-8を削除されました

このセットでは-Dfile.encoding=UTF-8は違いがないように見えました。

私はまだ上記と同じ失敗を得るためにdbに国際的なテキストを書くことができませんでした

これを使って mysqlデータベースの文字セットと照合順序をutf-8に変換する方法

utf8mb4を使用するようにすべてのデータベースを更新します。

ALTER DATABASE YOURDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ラングする必要があるものを提供するこのクエリを実行して下さい

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%')

エディタでコピーペースト出力をすべて置換します。正しいdbに接続したときにmysqlに何もポストバックしません。

それがすべて行われなければならなかったことであり、すべて私のために働くようです。 -Dfile.encoding=UTF-8が有効になっておらず、期待通りに動作しているように見えます

E2Aまだ問題がありますか?私は確かに本番に入っていますので、上で行ったことを確認する必要があることがわかります。そして、このシナリオで修正します。

show create table user

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

手動でレコードを更新しようとすると、まだラテン語が残っていることがわかります。

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

それでは絞り込みましょう。

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)

手短に言えば、私は更新を機能させるためにそのフィールドのサイズを縮小しなければなりませんでした。

今私が実行すると:

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

それはすべてうまくいく

10
Vahid

私の場合は、上記のすべてを試しましたが、何も機能しませんでした。私のデータベースは以下のようになります。

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

だから、私はすべてのテーブルで列の文字セットを調べる

show create table company;

列の文字セットがラテンであることがわかります。だからこそ、私はデータベースに中国語を挿入することはできません。

 ALTER TABLE company CONVERT TO CHARACTER SET utf8;

それはあなたを助けるかもしれません。 :)

5
crazy_phage

ただする

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

私は私のPLAY Javaアプリケーションでこの問題を抱えていました。これはその例外に対する私のスタックトレースです:

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

Io.Ebeanを使ってレコードを保存しようとしていました。私はutf8mb4照合順序でデータベースを再作成することでそれを修正し、すべてのテーブルがutf-8照合順序で再作成されるようにすべてのテーブルを再作成するためにplay evolutionを適用しました。

CREATE DATABASE inventory CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
3

私のRailsプロジェクトにも同じ問題がありました。

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

解決策1:Base64.encode64(subject)を使って文字列をbase64に変換する前に、Base64.decode64(subject)を使ってdbに保存します

解決策2:

手順1:件名列の文字セット(および照合順序)を次のように変更します。

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

ステップ2:database.ymlで使用する

encoding :utf8mb4
3
ravi

このエラーを解決するためにphpmyadminを使用していると仮定して、次の手順に従います。

  1. phpMyAdmin
  2. your_table
  3. 「構造タブ」
  4. フィールドの照合順序をlatin1_swedish_ci(またはそれがなんであれ)からutf8_general_ciに変更します。
3
Teo Mihaila

1つのフィールドだけに変更を適用したいのですが、フィールドをシリアル化してみてください。

class MyModel < ActiveRecord::Base
  serialize :content

  attr_accessible :content, :title
end
2
Paul Marclay

そのほとんどは、いくつかのUnicode文字が原因です。私の場合、それはルピー通貨記号でした。

これをすばやく修正するには、このエラーの原因となっているキャラクターを見つける必要がありました。テキスト全体をviのようなテキストエディタでコピーして、問題のある文字をテキストの文字に置き換えます。

2
BTR Naidu

あなたはメタHTMLでutf8mb4を設定する必要がありますそしてまたあなたのサーバーでtabelを変更し照合をutf8mb4に設定する必要があります

1
Sona Israyelyan

新しいMySQLテーブルを作成する場合は、作成時にすべての列の文字セットを指定できます。これにより、問題が修正されました。

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

詳細を読むことができます: https://dev.mysql.com/doc/refman/8.0/en/charset-column.html

1
amucunguzi

私の解決策は、varchar(255)からblobにカラムタイプを変更することです

1
zhuochen shen

これは推奨ソリューションではありません。しかし、共有する価値があります。私のプロジェクトはDBMSを古いMysqlから最新のもの(8)にアップグレードしているためです。しかし、DBMS構成(mysql)のみを変更して、テーブル構造を変更することはできません。 mysqlサーバーのソリューション。

Windows mysql 8.0.15 on mysql config検索

sql-mode = "....."

コメントを外します。または私の場合は単に入力/追加

sql-mode = "NO_ENGINE_SUBSTITUTION"

なぜ推奨されない解決策です。 latin1(私の場合)を使用すると、データは正常に挿入されますが、コンテンツは挿入されません(mysqlはエラーで応答しません!!)。たとえば、次のような情報を入力します

bla\x12

保存する

bla [](ボックス)

問題ありません。フィールドをUTF8に変更できます。しかし、小さな問題があります。2バイト(cmiiw)を超えるためWordが挿入されないため、他のソリューションに関する上記の回答は失敗します。ソリューションは、挿入データをボックスにします。合理的なのは、blobを使用することです。私の答えはスキップできます。

これに関連する別のテストは、保存前にコードでtf8_encodeを使用することでした。 latin1で使用し、成功しました(sql-modeを使用していません)! base64_encodeを使用した上記の回答と同じです。

テーブルの要件を分析し、他の形式からUTF8に変更しようとした私の提案

0
user2905554