Gdy klient MySQL wchodzi w interakcję z serwerem:
-
serwer odbiera dowolny tekst jedynie jako ciąg bajtów; klient wcześniej powiedział mu, jak taki tekst będzie zakodowany.
-
jeśli serwer musi następnie przechowywać ten tekst w tabeli, musi go transkodować do kodowania odpowiedniej kolumny (jeśli jest inna).
-
jeśli klient chce później pobrać taki tekst, serwer musi go transkodować do kodowania oczekiwanego przez klienta.
Jeśli kodowania używane przez klienta w krokach 1 i 3 są takie same (co zwykle ma miejsce, zwłaszcza gdy klient w obu przypadkach jest tą samą aplikacją), często pozostaje niezauważone, jeśli klient używa kodowania innego niż to, o którym mówi. Załóżmy na przykład, że klient mówi MySQL, że użyje latin1 , ale faktycznie wysyła dane w utf8 :
-
Ciąg
'Jazz–Man'jest wysyłany na serwer w UTF-8 jako0x4a617a7ae280934d616e. -
MySQL, dekodując te bajty w Windows-1252, rozumie, że reprezentują one ciąg
'Jazz–Man'. -
Aby przechowywać w
utf8kolumna, MySQL transkoduje ciąg do jego kodowania UTF-80x4a617a7ac3a2e282ace2809c4d616e. Można to zweryfikować za pomocąSELECT HEX(name) FROM lessons WHERE id=79510. -
Kiedy klient pobiera wartość, MySQL myśli, że chce ją w
latin1a więc transkoduje do kodowania Windows-12520x4a617a7ae280934d616e. -
Gdy klient otrzymuje te bajty, dekoduje je jako UTF-8 i dlatego rozumie, że ciąg to
'Jazz–Man'.
Wniosek :klient nie zdaje sobie sprawy, że coś jest nie tak. Problemy są wykrywane tylko wtedy, gdy inny klient (taki, który nie podaje błędnie swojego połączenia UTF-8 jako latin1 ) próbuje użyć tabeli. W Twoim przypadku miało to miejsce, gdy mysqldump uzyskał eksport danych; używając --default-character-set=latin1 --skip-set-charset opcje skutecznie zmusiły mysqldump do zachowywania się w ten sam sposób, co Twoja aplikacja, więc w efekcie uzyskano poprawnie zakodowane dane.
Aby rozwiązać problem w przyszłości, musisz:
-
Skonfiguruj swoją aplikację tak, aby poprawnie ustawiała zestaw znaków połączenia MySQL (np. ustaw
encoding: utf8wconfig/database.ymldla szyn); -
Przekoduj dane w Twojej bazie, np.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)(zauważ, że należy to zrobić dla każdej błędnie zakodowanej kolumny tekstu).
Pamiętaj też, że prawdopodobnie będziesz chciał wykonać te dwie czynności atomowo, co może wymagać trochę przemyślenia.