Когато MySQL клиент взаимодейства със сървъра:
-
сървърът получава всеки текст просто като низ от байтове; клиентът ще му е казал предварително как ще бъде кодиран такъв текст.
-
ако след това сървърът трябва да съхрани този текст в таблица, той трябва да го прекодира към кодирането на съответната колона (ако е различно).
-
ако клиентът впоследствие иска да извлече такъв текст, сървърът трябва да го транскодира до очакваното от клиента кодиране.
Ако кодировките, използвани от клиента в стъпки 1 и 3, са едни и същи (което обикновено се случва, особено когато клиентът и в двата случая е едно и също приложение), тогава често остава незабелязано, ако клиентът използва кодиране, различно от това, което е казал, че ще използва. Да предположим например, че клиентът казва на MySQL, че ще използва latin1
, но всъщност изпраща данни в utf8
:
-
Низът
'Jazz–Man'
се изпраща до сървъра в UTF-8 като0x4a617a7ae280934d616e
. -
MySQL, декодирайки тези байтове в Windows-1252, ги разбира като представляващи низа
'Jazz–Man'
. -
За съхраняване в
utf8
колона, MySQL прекодира низа към неговото UTF-8 кодиране0x4a617a7ac3a2e282ace2809c4d616e
. Това може да се провери с помощта наSELECT HEX(name) FROM lessons WHERE id=79510
. -
Когато клиентът извлече стойността, MySQL смята, че я иска на
latin1
и така прекодира към Windows-1252 кодиране0x4a617a7ae280934d616e
. -
Когато клиентът получи тези байтове, той ги декодира като UTF-8 и следователно разбира низа като
'Jazz–Man'
.
Заключение :клиентът не осъзнава, че нещо не е наред. Проблеми се откриват само когато е различен клиент (този, който не представя погрешно своята UTF-8 връзка като latin1
) се опитва да използва таблицата. Във вашия случай това се случи, когато mysqldump получи експортиране на данните; използвайки --default-character-set=latin1 --skip-set-charset
опциите ефективно принудиха mysqldump да се държи по същия счупен начин като вашето приложение, така че в крайна сметка се оказа с правилно кодирани данни.
За да коригирате проблема си в бъдеще, трябва:
-
Конфигурирайте приложението си така, че да задава правилно своя набор от символи за свързване към MySQL (напр. задайте
encoding: utf8
вconfig/database.yml
за Rails); -
Прекодирайте данните във вашата база данни, напр.
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(обърнете внимание, че това трябва да се направи за всяка неправилно кодирана текстова колона).
Също така имайте предвид, че вероятно ще искате да изпълните тези две действия атомарно, което може да изисква известно обмисляне.