java.sql.SQLException: Falscher Zeichenfolgenwert: '\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F…'

107

Ich habe den folgenden Zeichenfolgenwert: "walmart obama 👽💔"

Ich benutze MySQL und Java.

Ich erhalte die folgende Ausnahme: `java.sql.SQLException: Falscher Zeichenfolgenwert: '\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F ...'

Hier ist die Variable, in die ich einfügen möchte:

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

Mein Java-Code, der versucht, "walmart obama 👽💔" einzufügen, ist eine vorbereitete Anweisung. Also benutze ich die setString()Methode.

Es sieht so aus, als ob das Problem in der Codierung der Werte 👽💔 liegt. Wie kann ich das beheben? Zuvor habe ich Derby SQL verwendet und die Werte 👽💔 waren nur zwei Quadratmeter (ich denke, dies ist die Darstellung des Nullzeichens).

Jede Hilfe wird sehr geschätzt!

CodeKingPlusPlus
quelle
Scheint wie ein Duplikat von stackoverflow.com/questions/10957238/…
Joshua Davis
Wenn Sie die Datenbank erstellen, können Sie den Zeichensatz und die Sortierung wie CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Max Peng

Antworten:

145

Was Sie haben, ist EXTRATERRESTRIAL ALIEN (U+1F47D)und BROKEN HEART (U+1F494)was nicht in der mehrsprachigen Grundebene. Sie können nicht einmal in Java als ein Zeichen dargestellt werden "👽💔".length() == 4. Sie sind definitiv keine Nullzeichen und man sieht Quadrate, wenn Sie keine Schriftarten verwenden, die sie unterstützen.

MySQL unterstützt utf8nur die mehrsprachige Grundebene, und Sie müssen utf8mb4stattdessen Folgendes verwenden :

Für ein zusätzliches Zeichen kann utf8 das Zeichen überhaupt nicht speichern, während utf8mb4 vier Bytes benötigt, um es zu speichern. Da utf8 das Zeichen überhaupt nicht speichern kann, haben Sie keine zusätzlichen Zeichen in utf8-Spalten und müssen sich keine Gedanken über das Konvertieren von Zeichen oder den Verlust von Daten machen, wenn Sie utf8-Daten von älteren Versionen von MySQL aktualisieren.

Um diese Zeichen zu unterstützen, muss MySQL 5.5+ sein und Sie müssen es utf8mb4überall verwenden. Die Verbindungscodierung muss sein utf8mb4, der Zeichensatz muss sein utf8mb4und die Kollision muss sein utf8mb4. Für Java ist es immer noch gerecht "utf-8", aber MySQL braucht eine Unterscheidung.

Ich weiß nicht, welchen Treiber Sie verwenden, aber eine treiberunabhängige Methode zum Festlegen des Verbindungszeichensatzes besteht darin, die folgende Abfrage zu senden:

SET NAMES 'utf8mb4'

Gleich nach dem Herstellen der Verbindung.

Siehe auch dies für Connector / J :

14.14: Wie kann ich 4-Byte-UTF8, utf8mb4 mit Connector / J verwenden?

Um 4-Byte-UTF8 mit Connector / J zu verwenden, konfigurieren Sie den MySQL-Server mit character_set_server = utf8mb4. Connector / J verwendet diese Einstellung dann, solange in der Verbindungszeichenfolge keine Zeichencodierung festgelegt wurde . Dies entspricht der automatischen Erkennung des Zeichensatzes.

Passen Sie auch Ihre Spalten und Ihre Datenbank an:

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

Auch hier muss Ihre MySQL-Version für die Unterstützung von utf8mb4 relativ aktuell sein.

Esailija
quelle
Schauen Sie sich meinen anderen verwandten Beitrag an: stackoverflow.com/questions/13748170/… . Wenn Sie es beantworten können, haben Sie auch diese Frage beantwortet. Der andere Beitrag enthält weitere Details zu dem, was ich getan habe.
CodeKingPlusPlus
1
@CodeKingPlusPlus haben Sie alles in Ihrer Datenbank geändert utf8mb4, es sieht so aus, als ob Sie noch verwenden utf8_general_ci..
Esailija
1
Machen Sie keine "SET NAMES" mit Connector / J: dev.mysql.com/doc/connector-j/en/… Do not issue the query set names with Connector/J, as the driver will not detect that the character set has changed, and will continue to use the character set detected during the initial connection setup.
bcoughlan
1
Wenn Sie nur die Zeichen von außerhalb des BMP entfernen
möchten,
2
Ich habe das gleiche Problem, habe die obigen Schritte ausgeführt, wurde aber erst behoben, als der Zeichensatzserver = utf8mb4 in C: \ ProgramData \ MySQL \ MySQL Server 5.7 \ my.ini
fattah.safa
16

Alles in allem müssen Sie zum Speichern von Symbolen, für die 4 Byte erforderlich sind, das Characher-Set und die Sortierung aktualisieren für utf8mb4:

  1. Datenbanktabelle / -spalte: alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. Datenbankserververbindung ( siehe )

In meiner Entwicklungsumgebung für # 2 ziehe ich es vor, beim Starten des Servers Parameter in der Befehlszeile festzulegen: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


Achten Sie übrigens auf das Connector / J-Verhalten mit SET NAMES 'utf8mb4':

Geben Sie die Namen der Abfragesätze nicht mit Connector / J aus, da der Treiber nicht erkennt, dass sich der Zeichensatz geändert hat, und weiterhin den Zeichensatz verwendet, der beim ersten Verbindungsaufbau erkannt wurde.

Vermeiden Sie es, characterEncodingParameter in der Verbindungs-URL festzulegen, da dies die konfigurierte Servercodierung überschreibt:

Verwenden Sie die Eigenschaft characterEncoding in der URL, mit der die Verbindung zum Server hergestellt wird, um die automatisch erkannte Codierung auf der Clientseite zu überschreiben.

Rilaby
quelle
15

Seltsamerweise fand ich, dass das ENTFERNEN &characterEncoding=UTF-8von dem JDBC urlbei ähnlichen Problemen den Trick für mich tat.

Basierend auf meinen Eigenschaften,

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

Ich denke, dies unterstützt das, was @Esailija oben gesagt hat, dh mein MySQL, das in der Tat 5,5 ist, findet seine eigene Lieblingsvariante der UTF-8-Codierung heraus.

(Beachten Sie, dass ich auch das spezifiziere, von dem InputStreamich lese, wie UTF-8im Java-Code, was wahrscheinlich nicht weh tut) ...

jsh
quelle
Vielleicht useUnicode=truewird es nicht einmal gebraucht? In meinem Fall hat es nur funktioniert, character_set_server=utf8mb4global auf dem Server (RDS-Parametergruppe) festzulegen und KEINE Zeichencodierung in der JDBC-URL zu haben.
Joshua Davis
6

Wie ich mein Problem gelöst habe.

ich hatte

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

In meiner jdbc-Verbindungs-URL im Ruhezustand habe ich den String-Datentyp in der Datenbank in Langtext geändert, was zuvor varchar war.


quelle
Erstellen Sie, wenn Sie diese Spalte nicht indiziert und relativ klein benötigen, aber ich kann diesen Trick für alle meine Spalten tun
shareef
3

Hängen Sie die Zeile useUnicode=true&amp;characterEncoding=UTF-8an Ihre JDBC-URL an.

In Ihrem Fall werden die Daten nicht mit UTF-8Codierung gesendet.

JHS
quelle
Wie füge ich das hinzu? In meiner Verbindungszeichenfolge? Ich benutze Netbeans, wenn das hilft.
CodeKingPlusPlus
Wie stellen Sie die Verbindung her?
JHS
DriverManager.getConnection ("jdbc: mysql: // localhost: #### / [dbName]", [Benutzername], [Passwort]);
CodeKingPlusPlus
Machen Sie es so - DriverManager.getConnection ("jdbc: mysql: // localhost: #### / [dbName]? UseUnicode = true & amp; characterEncoding = UTF-8", [Benutzername], [Passwort]);
JHS
1
Kratz das, ich habe das '?' Aber jetzt bin ich wieder auf dem gleichen Fehler wie der ursprüngliche Beitrag ...
CodeKingPlusPlus
3

Ich vor dem gleichen Problem und löste es durch die Einstellung Sortierungs zu utf8_general_ci für jede Spalte.

Appy
quelle
2

Ich denke, MySQL glaubt nicht, dass dies gültiger UTF8-Text ist. Ich habe versucht, eine Einfügung in eine Testtabelle mit derselben Spaltendefinition durchzuführen (die MySQL-Client-Verbindung war ebenfalls UTF8), und obwohl die Einfügung durchgeführt wurde, haben die Daten, die ich mit dem MySQL CLI-Client sowie JDBC abgerufen habe, die Werte nicht korrekt abgerufen. Um sicherzugehen, dass UTF8 korrekt funktioniert hat, habe ich ein "ö" anstelle eines "o" für Obama eingefügt:

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

Kleine Java-Anwendung zum Testen mit:

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();
        }
    }

}

Ausgabe:

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

Außerdem habe ich das gleiche Insert mit der JDBC-Verbindung versucht und es hat die gleiche Ausnahme ausgelöst, die Sie erhalten. Ich glaube, dass dies ein MySQL-Fehler ist. Vielleicht gibt es bereits einen Fehlerbericht über eine solche Situation.

Friek
quelle
Übrigens werden die Zeichen in Ihrer Zeichenfolge in Firefox und Chrome unter OSX nicht einmal korrekt angezeigt. Sie werden in meiner iTerm-Anwendung korrekt angezeigt. Ich denke, das ist schriftabhängig.
Friek
1

Ich hatte das gleiche Problem und nachdem ich sorgfältig gegen alle Zeichensätze vorgegangen war und festgestellt hatte, dass sie in Ordnung waren, stellte ich fest, dass die fehlerhafte Eigenschaft, die ich in meiner Klasse hatte, als @Column anstelle von @JoinColumn (javax.presistence; Hibernate) und kommentiert wurde es zerbrach alles.

jon
quelle
1

ausführen

show VARIABLES like "%char%”;

Finde den Zeichensatz-Server, wenn er nicht utf8mb4 ist.

setze es in deine my.cnf, wie

vim /etc/my.cnf

füge eine Zeile hinzu

character_set_server = utf8mb4

endlich mysql neu starten

Kevin Hawk
quelle
1
character_set_serverist die Option, NICHTcharacter-set-server
Arun SR
0

Diese Einstellung useOldUTF8Behavior = true hat bei mir gut funktioniert. Es gab keine falschen Zeichenfolgenfehler, aber es konvertierte Sonderzeichen wie à in mehrere Zeichen und speicherte sie in der Datenbank.

Um solche Situationen zu vermeiden, habe ich diese Eigenschaft aus dem JDBC-Parameter entfernt und stattdessen den Datentyp meiner Spalte in BLOB konvertiert. Das hat perfekt funktioniert.

Prithu Kumar
quelle
Könnten Sie bitte Ihrer Antwort mehr Deatil hinzufügen? (Code, Kommandanten usw.)
aBnormaLz
-2

Außerdem kann der Datentyp die Blob-Installation von Varchar oder Text verwenden.

barry xu
quelle
Sie wollen das nicht
ECostello