När en MySQL-klient interagerar med servern:
-
servern tar emot vilken text som helst bara som en sträng av bytes; klienten har tidigare berättat hur sådan text skulle kodas.
-
om servern sedan måste lagra den texten i en tabell, måste den omkoda den till kodningen för den relevanta kolumnen (om den är annorlunda).
-
om klienten senare vill hämta sådan text måste servern koda om den till den kodning som klienten förväntar sig.
Om kodningarna som används av klienten i steg 1 och 3 är samma (vilket vanligtvis är fallet, speciellt när klienten i båda fallen är samma applikation), då går det ofta obemärkt förbi om klienten använder en annan kodning än den den sa att den skulle göra. Anta till exempel att klienten säger till MySQL att den kommer att använda latin1
, men skickar faktiskt data i utf8
:
-
Strängen
'Jazz–Man'
skickas till servern i UTF-8 som0x4a617a7ae280934d616e
. -
MySQL, som avkodar dessa bytes i Windows-1252, förstår att de representerar strängen
'Jazz–Man'
. -
För att lagra i en
utf8
kolumn, omkodar MySQL strängen till dess UTF-8-kodning0x4a617a7ac3a2e282ace2809c4d616e
. Detta kan verifieras genom att användaSELECT HEX(name) FROM lessons WHERE id=79510
. -
När klienten hämtar värdet tror MySQL att den vill ha det i
latin1
och så omkodas till Windows-1252-kodningen0x4a617a7ae280934d616e
. -
När klienten tar emot dessa bytes avkodar den dem som UTF-8 och förstår därför att strängen är
'Jazz–Man'
.
Slutsats :klienten inser inte att något är fel. Problem upptäcks bara när en annan klient (en som inte anger sin UTF-8-anslutning felaktigt som latin1
) försöker använda tabellen. I ditt fall inträffade detta när mysqldump fick en export av data; med --default-character-set=latin1 --skip-set-charset
options tvingade effektivt mysqldump att bete sig på samma trasiga sätt som din applikation, så det slutade med korrekt kodad data.
För att åtgärda problemet framöver måste du:
-
Konfigurera din applikation så att den ställer in sin MySQL-anslutningsteckenuppsättning korrekt (t.ex. set
encoding: utf8
iconfig/database.yml
för skenor); -
Koda om data i din databas, t.ex.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(observera att detta måste göras för varje felkodad textkolumn).
Observera också att du förmodligen kommer att vilja utföra dessa två åtgärder atomärt, vilket kan kräva lite eftertanke.