Når en MySQL-klient interagerer med serveren:
-
serveren modtager enhver tekst blot som en streng af bytes; klienten vil tidligere have fortalt det, hvordan sådan tekst ville blive kodet.
-
hvis serveren derefter skal gemme denne tekst i en tabel, skal den omkode den til kodningen af den relevante kolonne (hvis forskellig).
-
hvis klienten efterfølgende ønsker at hente sådan tekst, skal serveren omkode den til den kodning, som klienten forventer.
Hvis kodningerne brugt af klienten i trin 1 og 3 er samme (hvilket normalt er tilfældet, især når klienten i begge tilfælde er den samme applikation), så går det ofte ubemærket hen, hvis klienten bruger en anden kodning end den, den sagde, den ville. Antag for eksempel, at klienten fortæller MySQL, at den vil bruge latin1
, men sender faktisk data i utf8
:
-
Strengen
'Jazz–Man'
sendes til serveren i UTF-8 som0x4a617a7ae280934d616e
. -
MySQL, der afkoder disse bytes i Windows-1252, forstår dem til at repræsentere strengen
'Jazz–Man'
. -
For at gemme i en
utf8
kolonne, omkoder MySQL strengen til dens UTF-8-kodning0x4a617a7ac3a2e282ace2809c4d616e
. Dette kan verificeres ved at brugeSELECT HEX(name) FROM lessons WHERE id=79510
. -
Når klienten henter værdien, tror MySQL, at den vil have den i
latin1
og så omkoder til Windows-1252-kodningen0x4a617a7ae280934d616e
. -
Når klienten modtager disse bytes, afkoder den dem som UTF-8 og forstår derfor, at strengen er
'Jazz–Man'
.
Konklusion :Klienten indser ikke, at der er noget galt. Problemer opdages kun, når en anden klient (en, der ikke angiver sin UTF-8-forbindelse forkert som latin1
) forsøger at bruge tabellen. I dit tilfælde skete dette, da mysqldump opnåede en eksport af dataene; ved hjælp af --default-character-set=latin1 --skip-set-charset
muligheder tvang mysqldump til at opføre sig på samme ødelagte måde som din applikation, så det endte med korrekt kodede data.
For at løse dit problem fremover skal du:
-
Konfigurer din applikation, så den sætter sit MySQL-forbindelsestegnsæt korrekt (f.eks. sæt
encoding: utf8
iconfig/database.yml
for skinner); -
Omkode dataene i din database, f.eks.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(bemærk, at dette skal gøres for hver fejlkodet tekstkolonne).
Bemærk også, at du sandsynligvis vil udføre disse to handlinger atomært, hvilket kan kræve lidt eftertanke.