Quando un client MySQL interagisce con il server:
-
il server riceve qualsiasi testo semplicemente come una stringa di byte; il cliente gli avrà precedentemente detto come sarebbe stato codificato tale testo.
-
se poi il server deve memorizzare quel testo in una tabella, deve transcodificarlo nella codifica della colonna pertinente (se diversa).
-
se il client desidera successivamente recuperare tale testo, il server deve transcodificarlo nella codifica prevista dal client.
Se le codifiche utilizzate dal client nei passaggi 1 e 3 sono le identiche (cosa che di solito è il caso, specialmente quando il client in entrambi i casi è la stessa applicazione), quindi spesso passa inosservato se il client utilizza una codifica diversa da quella che avrebbe detto. Ad esempio, supponiamo che il client dica a MySQL che utilizzerà latin1
, ma in realtà invia i dati in utf8
:
-
La stringa
'Jazz–Man'
viene inviato al server in UTF-8 come0x4a617a7ae280934d616e
. -
MySQL, decodificando quei byte in Windows-1252, li interpreta per rappresentare la stringa
'Jazz–Man'
. -
Per memorizzare in un
utf8
colonna, MySQL transcodifica la stringa nella sua codifica UTF-80x4a617a7ac3a2e282ace2809c4d616e
. Questo può essere verificato utilizzandoSELECT HEX(name) FROM lessons WHERE id=79510
. -
Quando il client recupera il valore, MySQL pensa di volerlo in
latin1
e quindi transcodifica nella codifica Windows-12520x4a617a7ae280934d616e
. -
Quando il client riceve quei byte, li decodifica come UTF-8 e quindi interpreta la stringa come
'Jazz–Man'
.
Conclusione :il cliente non si accorge che c'è qualcosa che non va. I problemi vengono rilevati solo quando un client diverso (uno che non indica erroneamente la sua connessione UTF-8 come latin1
) tenta di utilizzare la tabella. Nel tuo caso, ciò si è verificato quando mysqldump ha ottenuto un'esportazione dei dati; usando il --default-character-set=latin1 --skip-set-charset
le opzioni hanno effettivamente forzato mysqldump a comportarsi nello stesso modo rotto della tua applicazione, quindi ha finito con i dati codificati correttamente.
Per risolvere il tuo problema in futuro, devi:
-
Configura la tua applicazione in modo che imposti correttamente il suo set di caratteri di connessione MySQL (ad es. set
encoding: utf8
inconfig/database.yml
per binari); -
Ricodifica i dati nel tuo database, ad es.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(nota che questo deve essere fatto per ogni colonna di testo codificata in modo errato).
Nota anche che probabilmente vorrai eseguire queste due azioni in modo atomico, il che potrebbe richiedere qualche riflessione.