Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

dados utf8 parecem bons no mysql, mas estão quebrados nos trilhos


Quando um cliente MySQL interage com o servidor:

  1. o servidor recebe qualquer texto meramente como uma sequência de bytes; o cliente terá informado previamente como tal texto seria codificado.

  2. 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).

  3. 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 como 0x4a617a7ae280934d616e .

  • MySQL, decodificando esses bytes no Windows-1252, os entende para representar a string 'Jazz–Man' .

  • Para armazenar em um utf8 coluna, o MySQL transcodifica a string para sua codificação UTF-8 0x4a617a7ac3a2e282ace2809c4d616e . Isso pode ser verificado usando SELECT HEX(name) FROM lessons WHERE id=79510 .

  • Quando o cliente recupera o valor, o MySQL pensa que o quer em latin1 e assim transcodifica para a codificação Windows-1252 0x4a617a7ae280934d616e .

  • 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:

  1. Configure seu aplicativo para que ele defina corretamente seu conjunto de caracteres de conexão MySQL (por exemplo, set encoding: utf8 em config/database.yml para Trilhos);

  2. 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.