Wanneer een MySQL-client interageert met de server:
-
de server ontvangt elke tekst alleen als een reeks bytes; de klant heeft hem eerder verteld hoe dergelijke tekst zou worden gecodeerd.
-
als de server die tekst vervolgens in een tabel moet opslaan, moet hij deze transcoderen naar de codering van de relevante kolom (indien anders).
-
als de client vervolgens dergelijke tekst wil ophalen, moet de server deze transcoderen naar de codering die door de client wordt verwacht.
Als de coderingen die door de client in stap 1 en 3 worden gebruikt, dezelfde zijn (wat meestal het geval is, vooral wanneer de client in beide gevallen dezelfde toepassing is), dan wordt het vaak onopgemerkt als de client een andere codering gebruikt dan hij zei dat het zou doen. Stel bijvoorbeeld dat de client MySQL vertelt dat het latin1
. zal gebruiken , maar verzendt feitelijk gegevens in utf8
:
-
De string
'Jazz–Man'
wordt in UTF-8 naar de server gestuurd als0x4a617a7ae280934d616e
. -
MySQL, die die bytes decodeert in Windows-1252, begrijpt dat ze de tekenreeks
'Jazz–Man'
vertegenwoordigen . -
Opslaan in een
utf8
kolom, transcodeert MySQL de string naar zijn UTF-8-codering0x4a617a7ac3a2e282ace2809c4d616e
. Dit kan worden geverifieerd met behulp vanSELECT HEX(name) FROM lessons WHERE id=79510
. -
Wanneer de client de waarde ophaalt, denkt MySQL dat hij deze in
latin1
wil hebben en dus transcodeert naar de Windows-1252-codering0x4a617a7ae280934d616e
. -
Wanneer de client die bytes ontvangt, decodeert hij ze als UTF-8 en begrijpt daarom de tekenreeks als
'Jazz–Man'
.
Conclusie :de klant heeft niet door dat er iets aan de hand is. Problemen worden alleen gedetecteerd wanneer een andere client (een die zijn UTF-8-verbinding niet verkeerd aangeeft als latin1
) probeert de tabel te gebruiken. In uw geval gebeurde dit toen mysqldump een export van de gegevens kreeg; met behulp van de --default-character-set=latin1 --skip-set-charset
opties dwongen mysqldump in feite om zich op dezelfde kapotte manier te gedragen als uw applicatie, dus het eindigde met correct gecodeerde gegevens.
Om uw probleem in de toekomst op te lossen, moet u:
-
Configureer uw toepassing zodat deze de MySQL-verbindingstekenset correct instelt (bijv. stel
encoding: utf8
in inconfig/database.yml
voor rails); -
Hercodeer de gegevens in uw database, b.v.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(merk op dat dit moet worden gedaan voor elke verkeerd gecodeerde tekstkolom).
Houd er ook rekening mee dat je deze twee acties waarschijnlijk atomair wilt uitvoeren, wat misschien wat nadenken vereist.