Lorsqu'un client MySQL interagit avec le serveur :
-
le serveur reçoit tout texte simplement sous la forme d'une chaîne d'octets ; le client lui aura préalablement indiqué comment un tel texte serait encodé.
-
si le serveur doit ensuite stocker ce texte dans une table, il doit le transcoder dans l'encodage de la colonne concernée (si différent).
-
si le client souhaite par la suite récupérer ce texte, le serveur doit le transcoder selon l'encodage attendu par le client.
Si les encodages utilisés par le client aux étapes 1 et 3 sont les identiques (ce qui est généralement le cas, en particulier lorsque le client dans les deux cas est la même application), alors cela passe souvent inaperçu si le client utilise un encodage autre que celui qu'il a annoncé. Par exemple, supposons que le client indique à MySQL qu'il utilisera latin1
, mais envoie en fait des données en utf8
:
-
La chaîne
'Jazz–Man'
est envoyé au serveur en UTF-8 sous la forme0x4a617a7ae280934d616e
. -
MySQL, décodant ces octets dans Windows-1252, les comprend pour représenter la chaîne
'Jazz–Man'
. -
A stocker dans un
utf8
colonne, MySQL transcode la chaîne en son encodage UTF-80x4a617a7ac3a2e282ace2809c4d616e
. Cela peut être vérifié en utilisantSELECT HEX(name) FROM lessons WHERE id=79510
. -
Lorsque le client récupère la valeur, MySQL pense qu'il la veut en
latin1
et donc transcode vers l'encodage Windows-12520x4a617a7ae280934d616e
. -
Lorsque le client reçoit ces octets, il les décode en UTF-8 et comprend donc la chaîne comme étant
'Jazz–Man'
.
Conclusion :le client ne se rend pas compte que quelque chose ne va pas. Les problèmes ne sont détectés que lorsqu'un client différent (un client qui ne confond pas sa connexion UTF-8 en tant que latin1
) essaie d'utiliser la table. Dans votre cas, cela s'est produit lorsque mysqldump a obtenu une exportation des données ; en utilisant le --default-character-set=latin1 --skip-set-charset
Les options forçaient effectivement mysqldump à se comporter de la même manière cassée que votre application, donc elle s'est retrouvée avec des données correctement encodées.
Pour résoudre votre problème à l'avenir, vous devez :
-
Configurez votre application afin qu'elle définisse correctement son jeu de caractères de connexion MySQL (par exemple, définissez
encoding: utf8
dansconfig/database.yml
pour les rails); -
Recoder les données dans votre base de données, par ex.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(notez que cela doit être fait pour chaque colonne de texte mal codée).
Notez également que vous souhaiterez probablement effectuer ces deux actions de manière atomique, ce qui peut nécessiter une réflexion.