it-swarm.com.de

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

Ich habe den folgenden Stringwert: "Walmart Obama ????????"

Ich verwende MySQL und Java.

Ich erhalte folgende Ausnahme: `Java.sql.SQLException: Falscher Zeichenfolgewert: '\ xF0\x9F\x91\xBD\xF0\x9F ...'

Hier ist die Variable, in die ich einzufügen versuche:

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

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

Es sieht so aus, als ob das Problem die Kodierung der Werte ist. Wie kann ich das beheben? Zuvor habe ich Derby SQL verwendet und die Werte ???????? endete gerade zwei sqaures (ich denke, das ist die Darstellung des Nullzeichens)

Alle Hilfe wird sehr geschätzt!

86

Was Sie haben, ist EXTRATERRESTRIAL ALIEN (U+1F47D) und BROKEN HEART (U+1F494) / welche Sind nicht in der grundlegenden mehrsprachigen Ebene. Sie können in Java nicht einmal als ein Zeichen, "????????".length() == 4, dargestellt werden. Sie sind definitiv keine Nullzeichen und es werden Quadrate angezeigt, wenn Sie keine Zeichensätze verwenden, die sie unterstützen.

MySQLs utf8 unterstützt nur grundlegende mehrsprachige Ebenen und Sie müssen stattdessen utf8mb4 verwenden :

Bei einem Zusatzzeichen kann utf8 das Zeichen überhaupt nicht speichern. utf8mb4 benötigt vier Byte, um es zu speichern. Da utf8 nicht speichern kann das Zeichen überhaupt haben Sie keine zusätzlichen Zeichen in utf8-Spalten, und Sie müssen sich keine Gedanken um die Konvertierung von Zeichen oder .__ machen. Datenverlust beim Upgrade von utf8-Daten von älteren MySQL-Versionen.

Um diese Zeichen zu unterstützen, muss Ihr MySQL 5.5 oder höher sein und Sie müssen utf8mb4 überall verwenden. Die Verbindungskodierung muss utf8mb4 sein, der Zeichensatz muss utf8mb4 sein und die Kollision muss utf8mb4 sein. Für Java ist es immer noch nur "utf-8", aber MySQL muss unterschieden werden.

Ich weiß nicht, welchen Treiber Sie verwenden, aber eine treiberunabhängige Methode zum Festlegen des Verbindungszeichensatzes besteht im Senden der Abfrage:

SET NAMES 'utf8mb4'

Gleich nach dem Verbindungsaufbau. 

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 dann diese Einstellung solange characterEncoding in der Verbindung not gesetzt ist string. Dies entspricht der automatischen Erkennung des Zeichensatzes.

Passen Sie auch Ihre Spalten und Datenbanken an:

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

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

121
Esailija

Komischerweise fand ich heraus, dass das Entfernen von &characterEncoding=UTF-8 aus dem JDBC url mit ähnlichen Problemen den Trick für mich bewältigte.

Basierend auf meinen Eigenschaften,

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

Ich denke, das unterstützt das, was @Esailija oben gesagt hat, d. H. Mein MySQL, das in der Tat 5,5 ist, ermittelt seine eigene Lieblingsvariante der UTF-8-Codierung.

(Beachten Sie, ich gebe auch die InputStream, von der ich im Java-Code als UTF-8 lese, was wahrscheinlich nicht weh tut) ...

14
jsh

Alles in allem müssen zum Speichern von Symbolen, die 4 Byte benötigen, der Zeichensatz und die Sortierung für utf8mb4 aktualisiert werden:

  1. datenbanktabelle/Spalte: alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. datenbankserver-Verbindung ( siehe )

In meiner Entwicklungsumgebung für # 2 möchte ich beim Starten des Servers vorzugsweise Parameter in der Befehlszeile festlegen: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


Übrigens, achten Sie auf Connector/J Verhalten mit SET NAMES 'utf8mb4':

Vergeben Sie die Abfragesatznamen nicht mit Connector/J, da der Treiber nicht erkennt, dass sich der Zeichensatz geändert hat, und er den Zeichensatz weiterhin verwendet, der beim ersten Verbindungsaufbau erkannt wurde.

Vermeiden Sie es, den Parameter characterEncoding in der Verbindungs-URL einzustellen, da er die konfigurierte Serverkodierung überschreibt: 

Um die automatisch erkannte Kodierung auf der Clientseite zu überschreiben, verwenden Sie die characterEncoding -Eigenschaft in der URL, die für die Verbindung zum Server verwendet wird.

12
rilaby

Wie habe ich mein Problem gelöst?.

Ich hatte

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

In meinem Ruhezustand jdbc Verbindungs-URL und ich änderte den String-Datentyp in Langtext in der Datenbank, was vorher varchar war.

6
Indrek Ruubel

Ich war mit dem gleichen Problem konfrontiert und habe es gelöst, indem ich für jede Spalte die Option Collation auf utf8_general_ci gesetzt habe.

3
Appy

Ich glaube, MySQL glaubt nicht, dass dies ein gültiger UTF8-Text ist. Ich habe eine Einfügung in eine Testtabelle mit derselben Spaltendefinition versucht (MySQL-Client-Verbindung war auch UTF8), und obwohl die Einfügung durchgeführt wurde, riefen die mit dem MySQL-CLI-Client abgerufenen Daten sowie JDBC die Werte nicht korrekt ab. Um sicher zu sein, dass UTF8 korrekt funktioniert hat, habe ich für Obama ein "ö" anstelle eines "o" eingefügt:

[email protected]:~$ mysql -vvv test < insert.sql 
--------------
insert into utf8_test values(_utf8 "walmart öbama ????????")
--------------

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

[email protected]:~$ 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:

[email protected]:~/workspaces/Java/javatest/bin$ Java test.sql.Test
test string=walmart öbama ????????
retrieved="walmart öbama "

Ich habe auch die gleiche Einfügung mit der JDBC-Verbindung ausprobiert und 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 ..

2
Friek

Ich hatte das gleiche Problem und nachdem ich sorgfältig gegen alle Zeichensätze vorgegangen war und festgestellt hatte, dass alles in Ordnung war, erkannte ich, dass das verworrene Eigentum, das ich in meiner Klasse hatte, als @Column anstelle von @JoinColumn (javax.presistence; hibernate) und kommentiert wurde es zerbrach alles.

1
jon

execute

show VARIABLES like "%char%”;

finde den Zeichensatz-Server, wenn nicht utf8mb4.

setze es in deine my.cnf, wie

vim /etc/my.cnf

eine Zeile hinzufügen 

character-set-server = utf8mb4

starten Sie zuletzt mysql neu

1
Kevin Hawk

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

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

1
JHS

Diese Einstellung useOldUTF8Behavior = true hat für mich gut funktioniert. Es wurden keine fehlerhaften Zeichenfolgenfehler ausgegeben, es wurden jedoch Sonderzeichen wie à in mehrere Zeichen konvertiert und in der Datenbank gespeichert.

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. 

0
Prithu Kumar