Wenn ein MySQL-Client mit dem Server interagiert:
-
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.
-
Wenn der Server diesen Text dann in einer Tabelle speichern muss, muss er ihn in die Codierung der relevanten Spalte (falls abweichend) umcodieren.
-
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 als0x4a617a7ae280934d616e
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-Codierung0x4a617a7ac3a2e282ace2809c4d616e
. Dies kann mitSELECT 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-Codierung0x4a617a7ae280934d616e
. -
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:
-
Konfigurieren Sie Ihre Anwendung so, dass sie ihren MySQL-Verbindungszeichensatz korrekt einstellt (z. B. set
encoding: utf8
inconfig/database.yml
für Schienen); -
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.