Mysql
 sql >> Datenbank >  >> RDS >> Mysql

UTF8-Daten sehen in MySQL gut aus, sind aber in Schienen defekt

Wenn ein MySQL-Client mit dem Server interagiert:

  1. der Server empfängt jeden Text lediglich als eine Folge von Bytes; der Client wird ihm zuvor mitgeteilt haben, wie dieser Text codiert werden würde.

  2. Wenn der Server diesen Text dann in einer Tabelle speichern muss, muss er ihn in die Codierung der relevanten Spalte (falls abweichend) umcodieren.

  3. Wenn der Client anschließend solchen Text abrufen möchte, muss der Server ihn in die vom Client erwartete Codierung umcodieren.

Wenn die vom Client in den Schritten 1 und 3 verwendeten Codierungen gleich sind (was normalerweise der Fall ist, insbesondere wenn der Client in beiden Fällen dieselbe Anwendung ist), dann bleibt es oft unbemerkt, wenn der Client eine andere Codierung verwendet als die, die er angegeben hat. Angenommen, der Client teilt MySQL mit, dass er latin1 verwenden wird , sendet aber tatsächlich Daten in utf8 :

  • Die Zeichenfolge 'Jazz–Man' wird in UTF-8 als 0x4a617a7ae280934d616e an den Server gesendet .

  • MySQL, das diese Bytes in Windows-1252 dekodiert, versteht sie als Darstellung der Zeichenkette 'Jazz–Man' .

  • Zum Speichern in einem utf8 -Spalte transcodiert MySQL den String in seine UTF-8-Codierung 0x4a617a7ac3a2e282ace2809c4d616e . Dies kann mit SELECT HEX(name) FROM lessons WHERE id=79510 überprüft werden .

  • Wenn der Client den Wert abruft, denkt MySQL, dass er ihn in latin1 haben möchte und transcodiert so in die Windows-1252-Codierung 0x4a617a7ae280934d616e .

  • Wenn der Client diese Bytes empfängt, dekodiert er sie als UTF-8 und versteht die Zeichenfolge daher als 'Jazz–Man' .

Fazit :Der Kunde merkt nicht, dass etwas nicht stimmt. Probleme werden nur erkannt, wenn ein anderer Client (einer, der seine UTF-8-Verbindung nicht falsch als latin1 ) versucht, die Tabelle zu verwenden. In Ihrem Fall geschah dies, als mysqldump einen Export der Daten erhielt; mit --default-character-set=latin1 --skip-set-charset Optionen zwangen mysqldump effektiv dazu, sich genauso fehlerhaft zu verhalten wie Ihre Anwendung, sodass es am Ende korrekt codierte Daten erhielt.

Um Ihr Problem in Zukunft zu beheben, müssen Sie:

  1. Konfigurieren Sie Ihre Anwendung so, dass sie ihren MySQL-Verbindungszeichensatz korrekt einstellt (z. B. set encoding: utf8 in config/database.yml für Schienen);

  2. Recodieren Sie die Daten in Ihrer Datenbank, z. UPDATE lessons SET name = BINARY CONVERT(name USING latin1) (Beachten Sie, dass dies für jede falsch codierte Textspalte durchgeführt werden muss).

Beachten Sie auch, dass Sie diese beiden Aktionen wahrscheinlich atomar ausführen möchten, was einige Überlegungen erfordern kann.