web-dev-qa-db-ja.com

java.sql.SQLException:不適切な文字列値: '\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F ...'

次の文字列値があります: "walmart obama ????????"

MySQLとJavaを使用しています。

次の例外が発生しています: `Java.sql.SQLException:Incorrect string value: '\ xF0\x9F\x91\xBD\xF0\x9F ...'

ここに私が挿入しようとしている変数があります:

var1 varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL`

「ウォルマートオバマ????????」を挿入しようとしている私のJavaコードpreparedStatementです。そこで、setString()メソッドを使用しています。

問題は値のエンコーディングのようです????????。どうすれば修正できますか?以前は、Derby SQLと値を使用していました????????ちょうど2平方メートルになりました(これはヌル文字の表現だと思います)

すべてのヘルプは大歓迎です!

92

持っているのは EXTRATERRESTRIAL ALIEN (U+1F47D)BROKEN HEART (U+1F494) で、これらは基本的な多言語面にはありません。 Javaでは、1つの文字"????????".length() == 4として表現することさえできません。それらは間違いなくヌル文字ではなく、それらをサポートするフォントを使用していない場合は正方形が表示されます。

MySQLのutf8は基本的な多言語プレーンのみをサポートし、代わりにutf8mb4を使用する必要があります

補助文字の場合、utf8はその文字をまったく格納できませんが、utf8mb4は格納に4バイトを必要とします。 utf8は文字をまったく格納できないため、utf8列に補助文字はなく、古いバージョンのMySQLからutf8データをアップグレードするときに文字の変換やデータの損失を心配する必要はありません。

したがって、これらの文字をサポートするには、MySQLが5.5以上であり、utf8mb4をすべての場所で使用する必要があります。接続エンコードはutf8mb4である必要があり、文字セットはutf8mb4である必要があり、照合はutf8mb4である必要があります。 Javaの場合、まだ"utf-8"のままですが、MySQLには区別が必要です。

使用しているドライバーはわかりませんが、ドライバーに依存しない接続文字セットを設定する方法は、クエリを送信することです。

SET NAMES 'utf8mb4'

接続を確立した直後。

Connector/Jもご覧ください

14.14:Connector/Jで4バイトUTF8、utf8mb4を使用するにはどうすればよいですか?

Connector/Jで4バイトUTF8を使用するには、character_set_server = utf8mb4でMySQLサーバーを設定します。 Connector/Jはその設定を使用しますcharacterEncodingがnotが接続文字列に設定されている限り。これは、文字セットの自動検出と同等です。

列とデータベースも調整します。

var1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL

繰り返しますが、utf8mb4をサポートするには、MySQLのバージョンが比較的最新である必要があります。

128
Esailija

全体として、4バイトを必要とするシンボルを保存するには、utf8mb4の文字セットと照合を更新する必要があります。

  1. データベーステーブル/列:alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. データベースサーバー接続( 参照

#2の開発環境では、サーバーの起動時にコマンドラインでパラメーターを設定することを好みます:mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


ところで、 Connector/Jの動作 with SET NAMES 'utf8mb4'に注意してください:

ドライバーは文字セットが変更されたことを検出せず、初期接続セットアップ中に検出された文字セットを引き続き使用するため、Connector/Jでクエリセット名を発行しないでください。

接続URLでcharacterEncodingパラメーターを設定しないでください。設定されたサーバーエンコードがオーバーライドされるためです。

クライアント側で自動的に検出されたエンコードをオーバーライドするには、サーバーへの接続に使用されるURLでcharacterEncodingプロパティを使用します。

15
rilaby

奇妙なことに、&characterEncoding=UTF-8からJDBC urlを削除すると、同様の問題が発生することがわかりました。

私の特性に基づいて、

jdbc_url=jdbc:mysql://localhost:3306/dbName?useUnicode=true

これは@Esailijaが上記したことをサポートしていると思います。つまり、MySQL(実際には5.5)は、UTF-8エンコーディングの好みのフレーバーを見つけています。

(注:JavaコードでUTF-8として読み取り中のInputStreamも指定しているため、おそらく問題はありません)...

14
jsh

問題をどのように解決したか。

持っていた

?useUnicode=true&amp;characterEncoding=UTF-8

休止状態のjdbc接続URLで、データベースの文字列データ型をロングテキストに変更しました。これは以前はvarcharでした。

6
Indrek Ruubel

同じ問題に直面し、各列の照合tf8_general_ciに設定することで解決しました。

3
Appy

MySQLはこれが有効なUTF8テキストであるとは考えていません。同じ列定義を持つテストテーブルで挿入を試みました(mysqlクライアント接続もUTF8でした)。挿入は行いましたが、MySQL CLIクライアントとJDBCで取得したデータは値を正しく取得しませんでした。 UTF8が正しく機能することを確認するために、オバマの「o」の代わりに「ö」を挿入しました。

johan@maiden:~$ mysql -vvv test < insert.sql 
--------------
insert into utf8_test values(_utf8 "walmart öbama ????????")
--------------

Query OK, 1 row affected, 1 warning (0.12 sec)

johan@maiden:~$ file insert.sql 
insert.sql: UTF-8 Unicode text

テスト対象の小さなJavaアプリケーション:

package test.sql;

import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.PreparedStatement;
import Java.sql.ResultSet;

public class Test
{

    public static void main(String[] args)
    {
        System.out.println("test string=" + "walmart öbama ????????");
        String url = "jdbc:mysql://hostname/test?useUnicode=true&characterEncoding=UTF-8";
        try
        {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            Connection c = DriverManager.getConnection(url, "username", "password");
            PreparedStatement p = c.prepareStatement("select * from utf8_test");
            p.execute();
            ResultSet rs = p.getResultSet();
            while (!rs.isLast())
            {
                rs.next();
                String retrieved = rs.getString(1);
                System.out.println("retrieved=\"" + retrieved + "\"");

            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

出力:

johan@appel:~/workspaces/Java/javatest/bin$ Java test.sql.Test
test string=walmart öbama ????????
retrieved="walmart öbama "

また、JDBC接続で同じ挿入を試みましたが、同じ例外がスローされました。これはMySQLのバグだと思います。たぶん、そのような状況についてのバグレポートがあるかもしれません。

2
Friek

useUnicode=true&amp;characterEncoding=UTF-8をjdbcのURLに追加します。

あなたの場合、データはUTF-8エンコーディングを使用して送信されていません。

2
JHS

私は同じ問題を抱えていたので、すべての文字セットを注意深く調べて、それらが正しいことを発見した後、クラスにあるバグのあるプロパティに@JoinColumn(javax.presistence; hibernate)ではなく@Columnの注釈が付けられていることに気付きましたそれはすべてを壊していました。

1
jon

execute

show VARIABLES like "%char%”;

がutf8mb4でない場合、character-set-serverを見つけます。

次のようにmy.cnfに設定します

vim /etc/my.cnf

一行追加する

character_set_server = utf8mb4

最後にmysqlを再起動します

1
Kevin Hawk

この設定useOldUTF8Behavior = trueは、私にとってはうまくいきました。不正な文字列エラーは発生しませんでしたが、Ãのような特殊文字を複数の文字に変換し、データベースに保存しました。

このような状況を回避するために、JDBCパラメーターからこのプロパティを削除し、代わりに列のデータ型をBLOBに変換しました。これは完璧に機能しました。

0
Prithu Kumar