java.sql.SQLException: valore stringa non corretto: "\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F…"


107

Ho il seguente valore di stringa: "walmart obama 👽💔"

Sto usando MySQL e Java.

Ricevo la seguente eccezione: `java.sql.SQLException: valore stringa non corretto: '\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F ...'

Ecco la variabile in cui sto cercando di inserire:

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

Il mio codice Java che sta cercando di inserire "walmart obama 👽💔" è una dichiarazione preparata. Quindi sto usando il setString()metodo.

Sembra che il problema sia la codifica dei valori 👽💔. Come posso risolvere questo problema? In precedenza stavo usando Derby SQL ei valori 👽💔 finivano per essere due quadrati (penso che questa sia la rappresentazione del carattere nullo)

Tutto l'aiuto è molto apprezzato!



Quando crei il database, puoi fornire il set di caratteri e le regole di confronto in questo modo:CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Max Peng

Risposte:


145

Quello che hai è EXTRATERRESTRIAL ALIEN (U+1F47D)eBROKEN HEART (U+1F494) che non sono nel piano multilingue di base. Non possono essere anche rappresentati in Java come un char, "👽💔".length() == 4. Non sono sicuramente caratteri nulli e si vedranno dei quadrati se non si utilizzano caratteri che li supportano.

MySQL utf8supporta solo il piano multilingue di base e devi usare utf8mb4invece :

Per un carattere supplementare, utf8 non può memorizzare affatto il carattere, mentre utf8mb4 richiede quattro byte per memorizzarlo. Poiché utf8 non è in grado di memorizzare affatto il carattere, non sono presenti caratteri supplementari nelle colonne utf8 e non è necessario preoccuparsi di convertire i caratteri o perdere dati quando si aggiornano i dati utf8 da versioni precedenti di MySQL.

Quindi, per supportare questi caratteri, il tuo MySQL deve essere 5.5+ e devi usarlo utf8mb4ovunque. La codifica della connessione deve essere utf8mb4, il set di caratteri deve essere utf8mb4e la collazione deve essere utf8mb4. Per Java è ancora solo "utf-8", ma MySQL ha bisogno di una distinzione.

Non so quale driver stai utilizzando, ma un modo indipendente dal driver per impostare il set di caratteri di connessione è inviare la query:

SET NAMES 'utf8mb4'

Subito dopo aver effettuato la connessione.

Vedi anche questo per Connector / J :

14.14: Come posso usare UTF8 a 4 byte, utf8mb4 con Connector / J?

Per utilizzare UTF8 a 4 byte con Connector / J, configurare il server MySQL con character_set_server = utf8mb4. Connector / J utilizzerà quindi tale impostazione fintanto che characterEncoding non è stato impostato nella stringa di connessione . Ciò equivale al rilevamento automatico del set di caratteri.

Modifica anche le colonne e il database:

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

Ancora una volta, la tua versione di MySQL deve essere relativamente aggiornata per il supporto di utf8mb4.


Controlla il mio altro post correlato: stackoverflow.com/questions/13748170/… . Se puoi rispondere, avrai risposto anche a questa domanda. L'altro post contiene maggiori dettagli su ciò che ho fatto.
CodeKingPlusPlus

1
@CodeKingPlusPlus hai cambiato tutto nel tuo database in utf8mb4, sembra che tu stia ancora usando utf8_general_ci..
Esailija

1
Non fare "SET NAMES" con 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
Nel caso in cui si desidera ottenere solo liberarsi dei personaggi da fuori BMP invece di trattare con il pasticcio di cambiare il vostro DB, vedere qui: stackoverflow.com/questions/4035562/...
Indigenuity

2
Ho lo stesso problema, ho seguito i passaggi precedenti ma non sono stato risolto fino a quando non ho cambiato il set di caratteri-server = utf8mb4 in C: \ ProgramData \ MySQL \ MySQL Server 5.7 \ my.ini
fattah.safa

16

Tutto sommato, per salvare i simboli che richiedono 4 byte è necessario aggiornare il set di caratteri e le regole di confronto per utf8mb4:

  1. tabella / colonna database: alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. connessione al database server ( vedi )

Nel mio ambiente di sviluppo per # 2 preferisco impostare i parametri sulla riga di comando all'avvio del server: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


btw, prestare attenzione al comportamento del connettore / J con SET NAMES 'utf8mb4':

Non emettere i nomi dei set di query con Connector / J, poiché il driver non rileverà che il set di caratteri è cambiato e continuerà a utilizzare il set di caratteri rilevato durante l'impostazione della connessione iniziale.

Ed evita di impostare il characterEncodingparametro nell'URL di connessione poiché sovrascriverà la codifica del server configurata:

Per sovrascrivere la codifica rilevata automaticamente sul lato client, utilizzare la proprietà characterEncoding nell'URL utilizzato per connettersi al server.


15

Stranamente, ho scoperto che RIMUOVERE &characterEncoding=UTF-8da JDBC urlha funzionato per me con problemi simili.

In base alle mie proprietà,

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

Penso che questo supporti ciò che @Esailija ha detto sopra, cioè il mio MySQL, che è effettivamente 5.5, sta cercando di capire il suo gusto preferito di codifica UTF-8.

(Nota, sto anche specificando il InputStreamche sto leggendo come UTF-8nel codice java, che probabilmente non fa male) ...


Forse useUnicode=truenon è nemmeno necessario? Nel mio caso l'unica cosa che ha funzionato è l'impostazione character_set_server=utf8mb4globale sul server (gruppo di parametri RDS) e NON avere alcuna codifica dei caratteri nell'URL JDBC.
Joshua Davis

6

Come ho risolto il mio problema.

avevo

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

Nel mio URL di connessione jdbc di ibernazione e ho cambiato il tipo di dati della stringa in longtext nel database, che prima era varchar.


Ottimo se non hai bisogno di quella colonna indicizzata ed è relativamente piccola, ma posso fare questo trucco per tutte le mie colonne però
shareef

3

Aggiungi la riga useUnicode=true&amp;characterEncoding=UTF-8 al tuo URL jdbc.

Nel tuo caso i dati non vengono inviati utilizzando la UTF-8codifica.


Come lo aggiungo? Nella mia stringa di connessione? Sto usando Netbeans se questo aiuta.
CodeKingPlusPlus

Come stai creando la connessione?
JHS

DriverManager.getConnection ("jdbc: mysql: // localhost: #### / [dbName]", [nome utente], [password]);
CodeKingPlusPlus

Fai così - DriverManager.getConnection ("jdbc: mysql: // localhost: #### / [dbName]? UseUnicode = true & amp; characterEncoding = UTF-8", [nome utente], [password]);
JHS

1
Gratta quello, ho dimenticato il "?" Ma ora sono tornato allo stesso errore del post originale ...
CodeKingPlusPlus

3

Ho affrontato lo stesso problema e l'ho risolto impostando le regole di confronto su utf8_general_ci per ogni colonna.


2

Immagino che MySQL non creda che questo sia un testo UTF8 valido. Ho provato un inserimento su una tabella di test con la stessa definizione di colonna (la connessione del client mysql era anche UTF8) e sebbene abbia fatto l'inserimento, i dati che ho recuperato con il client CLI MySQL e JDBC non hanno recuperato correttamente i valori. Per essere sicuro che UTF8 funzionasse correttamente, ho inserito una "ö" invece di una "o" per obama:

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

Piccola applicazione java da testare con:

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

}

Produzione:

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

Inoltre, ho provato lo stesso inserto con la connessione JDBC e ha generato la stessa eccezione che stai ricevendo. Credo che questo sia un bug di MySQL. Forse c'è già una segnalazione di bug su una situazione del genere ..


A proposito, i caratteri nella tua stringa non vengono nemmeno visualizzati correttamente sia in Firefox che in Chrome su OSX. Vengono visualizzati correttamente nella mia applicazione iTerm. Penso che questo dipenda dal carattere.
Friek

1

Ho avuto lo stesso problema e dopo aver esaminato attentamente tutti i set di caratteri e aver scoperto che andavano bene, mi sono reso conto che la proprietà con bug che avevo nella mia classe era annotata come @Column invece di @JoinColumn (javax.presistence; hibernate) e stava rompendo tutto.


1

eseguire

show VARIABLES like "%char%”;

trova il server del set di caratteri se non è utf8mb4.

impostalo nel tuo my.cnf, come

vim /etc/my.cnf

aggiungi una riga

character_set_server = utf8mb4

finalmente riavviare mysql


1
character_set_serverè l'opzione, NONcharacter-set-server
Arun SR

0

Questa impostazione useOldUTF8Behavior = true ha funzionato bene per me. Non ha fornito errori di stringa errata ma ha convertito caratteri speciali come à in più caratteri e salvati nel database.

Per evitare tali situazioni, ho rimosso questa proprietà dal parametro JDBC e invece ho convertito il tipo di dati della mia colonna in BLOB. Questo ha funzionato perfettamente.


Potresti per favore aggiungere più dettagli alla tua risposta? (codice, commants, ecc.)
aBnormaLz

-2

Inoltre, il tipo di dati può utilizzare l'installazione BLOB di varchar o text.


Tu non vuoi che
ECostello
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.