Mysql
 sql >> Base de données >  >> RDS >> Mysql

les données utf8 semblent bien dans mysql mais sont cassées dans les rails

Lorsqu'un client MySQL interagit avec le serveur :

  1. 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é.

  2. 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).

  3. 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 forme 0x4a617a7ae280934d616e .

  • 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-8 0x4a617a7ac3a2e282ace2809c4d616e . Cela peut être vérifié en utilisant SELECT 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-1252 0x4a617a7ae280934d616e .

  • 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 :

  1. Configurez votre application afin qu'elle définisse correctement son jeu de caractères de connexion MySQL (par exemple, définissez encoding: utf8 dans config/database.yml pour les rails);

  2. 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.