Cuando un cliente MySQL interactúa con el servidor:
-
el servidor recibe cualquier texto simplemente como una cadena de bytes; el cliente le habrá dicho previamente cómo se codificaría dicho texto.
-
si el servidor tiene que almacenar ese texto en una tabla, debe transcodificarlo a la codificación de la columna relevante (si es diferente).
-
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 como0x4a617a7ae280934d616e
. -
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-80x4a617a7ac3a2e282ace2809c4d616e
. Esto se puede verificar usandoSELECT 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-12520x4a617a7ae280934d616e
. -
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:
-
Configure su aplicación para que establezca correctamente su conjunto de caracteres de conexión MySQL (por ejemplo, configure
encoding: utf8
enconfig/database.yml
para rieles); -
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.