Quando um cliente MySQL interage com o servidor:
-
o servidor recebe qualquer texto meramente como uma sequência de bytes; o cliente terá informado previamente como tal texto seria codificado.
-
se o servidor tiver que armazenar esse texto em uma tabela, ele deverá transcodificá-lo para a codificação da coluna relevante (se for diferente).
-
se o cliente posteriormente quiser recuperar tal texto, o servidor deve transcodificá-lo para a codificação esperada pelo cliente.
Se as codificações usadas pelo cliente nas etapas 1 e 3 forem as mesmas (que geralmente é o caso, especialmente quando o cliente em ambos os casos é o mesmo aplicativo), então muitas vezes passa despercebido se o cliente estiver usando uma codificação diferente daquela que disse que usaria. Por exemplo, suponha que o cliente diga ao MySQL que usará
latin1
, mas na verdade envia dados em utf8
:-
A string'Jazz–Man'
é enviado ao servidor em UTF-8 como0x4a617a7ae280934d616e
.
-
MySQL, decodificando esses bytes no Windows-1252, os entende para representar a string'Jazz–Man'
.
-
Para armazenar em umutf8
coluna, o MySQL transcodifica a string para sua codificação UTF-80x4a617a7ac3a2e282ace2809c4d616e
. Isso pode ser verificado usandoSELECT HEX(name) FROM lessons WHERE id=79510
.
-
Quando o cliente recupera o valor, o MySQL pensa que o quer emlatin1
e assim transcodifica para a codificação Windows-12520x4a617a7ae280934d616e
.
-
Quando o cliente recebe esses bytes, ele os decodifica como UTF-8 e, portanto, entende a string como'Jazz–Man'
.
Conclusão :o cliente não percebe que algo está errado. Os problemas só são detectados quando um cliente diferente (um que não declare incorretamente sua conexão UTF-8 como
latin1
) tenta usar a tabela. No seu caso, isso ocorreu quando o mysqldump obteve uma exportação dos dados; usando o --default-character-set=latin1 --skip-set-charset
options efetivamente forçaram o mysqldump a se comportar da mesma maneira quebrada que seu aplicativo, então acabou com dados codificados corretamente. Para corrigir o problema daqui para frente, você deve:
-
Configure seu aplicativo para que ele defina corretamente seu conjunto de caracteres de conexão MySQL (por exemplo, setencoding: utf8
emconfig/database.yml
para Trilhos);
-
Recodifique os dados em seu banco de dados, por exemplo.UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(observe que isso deve ser feito para cada coluna de texto codificada incorretamente).
Observe também que você provavelmente desejará realizar essas duas ações atomicamente, o que pode exigir alguma reflexão.