sql >> Base de Datos >  >> RDS >> Mysql

los datos utf8 se ven bien en mysql pero están rotos en los rieles

Cuando un cliente MySQL interactúa con el servidor:

  1. el servidor recibe cualquier texto simplemente como una cadena de bytes; el cliente le habrá dicho previamente cómo se codificaría dicho texto.

  2. si el servidor tiene que almacenar ese texto en una tabla, debe transcodificarlo a la codificación de la columna relevante (si es diferente).

  3. si el cliente desea recuperar dicho texto posteriormente, el servidor debe transcodificarlo a la codificación esperada por el cliente.

Si las codificaciones utilizadas por el cliente en los pasos 1 y 3 son las mismas (que suele ser el caso, especialmente cuando el cliente en ambos casos es la misma aplicación), a menudo pasa desapercibido si el cliente está utilizando una codificación diferente a la que dijo que usaría. Por ejemplo, suponga que el cliente le dice a MySQL que usará latin1 , pero en realidad envía datos en utf8 :

  • La cadena 'Jazz–Man' se envía al servidor en UTF-8 como 0x4a617a7ae280934d616e .

  • MySQL, al decodificar esos bytes en Windows-1252, entiende que representan la cadena 'Jazz–Man' .

  • Para almacenar en un utf8 columna, MySQL transcodifica la cadena a su codificación UTF-8 0x4a617a7ac3a2e282ace2809c4d616e . Esto se puede verificar usando SELECT HEX(name) FROM lessons WHERE id=79510 .

  • Cuando el cliente recupera el valor, MySQL piensa que lo quiere en latin1 y así se transcodifica a la codificación Windows-1252 0x4a617a7ae280934d616e .

  • Cuando el cliente recibe esos bytes, los decodifica como UTF-8 y, por lo tanto, entiende que la cadena es 'Jazz–Man' .

Conclusión :el cliente no se da cuenta de que algo anda mal. Los problemas solo se detectan cuando un cliente diferente (uno que no declara erróneamente su conexión UTF-8 como latin1 ) intenta usar la tabla. En su caso, esto ocurrió cuando mysqldump obtuvo una exportación de los datos; usando el --default-character-set=latin1 --skip-set-charset Las opciones efectivamente forzaron a mysqldump a comportarse de la misma manera que su aplicación, por lo que terminó con datos codificados correctamente.

Para solucionar su problema en el futuro, debe:

  1. Configure su aplicación para que establezca correctamente su conjunto de caracteres de conexión MySQL (por ejemplo, configure encoding: utf8 en config/database.yml para rieles);

  2. Recodifique los datos en su base de datos, p. UPDATE lessons SET name = BINARY CONVERT(name USING latin1) (Tenga en cuenta que esto debe hacerse para cada columna de texto mal codificada).

También tenga en cuenta que probablemente querrá realizar estas dos acciones de forma atómica, lo que puede requerir un poco de reflexión.