Cómo hacer que MySQL maneje UTF-8 correctamente

102

Una de las respuestas a una pregunta que hice ayer sugirió que debería asegurarme de que mi base de datos pueda manejar caracteres UTF-8 correctamente. ¿Cómo puedo hacer esto con MySQL?

Ben
fuente
4
Realmente espero que obtengamos una respuesta completa, que cubra varias versiones de MySQL, incompatibilidades, etc.
Edward Z. Yang
1
@ EdwardZ.Yang - Se introdujo MySQL 4.1 CHARACTER SETs; 5.1.24 interfirió con la intercalación de la aguda-s alemana (ß), que se rectificó al agregar otra intercalación en 5.1.62 (posiblemente empeorando las cosas); 5.5.3 completó utf8 con el nuevo juego de caracteres utf8mb4.
Rick James
1
Esta pregunta es bastante similar a esta ... Por favor, mire que stackoverflow.com/questions/3513773/…
Nyein Aung
Vale la pena señalar que la mayoría de estas respuestas son simplemente erróneas. No usar utf8. Solo admite caracteres de hasta 3 bytes. El conjunto de caracteres correcto que debe usar en MySQL es utf8mb4.
Brendan Byrd

Respuestas:

89

Actualizar:

Respuesta corta: casi siempre debería utilizar el utf8mb4juego de caracteres y la utf8mb4_unicode_ciintercalación.

Para alterar la base de datos:

ALTER DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Ver:

Respuesta original:

MySQL 4.1 y superior tiene un juego de caracteres predeterminado de UTF-8. Puede verificar esto en su my.cnfarchivo, recuerde configurar tanto el cliente como el servidor ( default-character-sety character-set-server).

Si tiene datos existentes que desea convertir a UTF-8, descargue su base de datos e impórtela de nuevo como UTF-8 asegurándose de:

  • usar SET NAMES utf8antes de consultar / insertar en la base de datos
  • usar DEFAULT CHARSET=utf8al crear nuevas tablas
  • en este punto, su cliente y servidor MySQL deberían estar en UTF-8 (ver my.cnf). recuerde que cualquier idioma que utilice (como PHP) también debe ser UTF-8. Algunas versiones de PHP usarán su propia biblioteca cliente MySQL, que puede no ser compatible con UTF-8.

Si desea migrar datos existentes, recuerde hacer una copia de seguridad primero. ¡Se pueden producir muchos cortes extraños de datos cuando las cosas no salen según lo planeado!

Algunos recursos:

Owen
fuente
29
Tengo entendido que utf8dentro de MySQL solo se refiere a un pequeño subconjunto de Unicode completo. Debería utilizar utf8mb4en su lugar para forzar el apoyo total. Consulte mathiasbynens.be/notes/mysql-utf8mb4 "Durante mucho tiempo, usé el juego de caracteres utf8 de MySQL para bases de datos, tablas y columnas, asumiendo que se asignaba a la codificación UTF-8 descrita anteriormente".
Aaron McDaid
7
MySQL nunca ha tenido un juego de caracteres predeterminado de UTF-8. 4.1 y 5.x hasta el último 5.7 todo uso latin1y latin1_swedish_cipara el juego de caracteres y colación predeterminados. Consulte la página "Colación y conjunto de caracteres del servidor" en el manual de MySQL para confirmarlo: dev.mysql.com/doc/refman/5.1/en/charset-server.html
Animism
2
@TimTisdall No necesita preocuparse por utf8mb4tener espacio de almacenamiento adicional cuando la mayoría del texto es ASCII. Aunque las charcadenas están preasignadas, las varcharcadenas no lo están; consulte las últimas líneas en esta página de documentación . Por ejemplo, char(10)se reservará pesimistamente 40 bytes bajo utf8mb4, pero varchar(10)asignará bytes de acuerdo con la codificación de longitud variable.
Kevin A. Naudé
1
@Kevin Creo que malinterpretaste eso. Creo que la longitud máxima de la fila es 64k. Solo puede hacer un campo utf8mb4 1/4 de eso porque tenía que reservar esa cantidad de espacio. Entonces, incluso si es ASCII, solo puede insertar 16k caracteres.
Tim Tisdall
1
@TimTisdall Oh, estás hablando de límites superiores. Sí, esos son más bajos. Afortunadamente, las versiones actuales de mysql se actualizarán automáticamente desde varchar(n)el texttipo de datos si intenta modificar un varchar(n)campo a un tamaño de byte mayor que el factible (mientras emite una advertencia). Un índice también tendrá un límite superior inferior en el peor de los casos, y eso puede presentar otros problemas.
Kevin A. Naudé
44

Para hacer esto 'permanente', en my.cnf:

[client]
default-character-set=utf8
[mysqld]
character-set-server = utf8

Para comprobarlo, vaya al cliente y muestre algunas variables:

SHOW VARIABLES LIKE 'character_set%';

Verifique que estén todos utf8, excepto ..._filesystem, que debería ser binaryy ..._dir, que apunta en algún lugar de la instalación de MySQL.

Javier
fuente
No funcionó en mi caso, pero creé el archivo my.cf en / etc con el contenido dado de todos modos. Solíacreate table my_name(field_name varchar(25) character set utf8);
Marek Barra
El "MOSTRAR VARIABLES COMO 'character_set%';" El comando me reveló el problema con mi conexión. ¡Gracias!
javsmo
1
Esto no es correcto. Lo que MySQL llama utf8no es UTF-8 "completo".
TWR Cole
32

MySQL 4.1 y superior tiene un juego de caracteres predeterminado al que llama, utf8pero que en realidad es solo un subconjunto de UTF-8 (permite solo caracteres de tres bytes y más pequeños).

Úselo utf8mb4como su juego de caracteres si desea UTF-8 "completo".

TWR Cole
fuente
5
Definitivamente de acuerdo, esta es la única respuesta correcta. utf8no incluye caracteres como emoticonos. utf8mb4hace. Consulte esto para obtener más información sobre cómo actualizar: mathiasbynens.be/notes/mysql-utf8mb4
jibai31
@Basti: mayormente correcto (latin1 era el predeterminado hasta hace poco), y no completo (no se analiza la inserción / selección correcta de datos codificados en utf8, ni la visualización en html).
Rick James
Respetuosamente, @RickJames, Basti dijo "hasta ahora". No recuerdo haber visto tu respuesta cuando publiqué esto.
TWR Cole
Por desgracia, hay alrededor de 5 síntomas claramente diferentes de los problemas de utf8 y alrededor de 4 cosas que los programadores hacen mal para causar problemas. La mayoría de las respuestas señalan solo una cosa que puede necesitar reparación. La pregunta original era amplia, por lo que la respuesta necesitaba todas las 4. Quizás Basti estaba familiarizado con un síntoma para el cual su único aspecto era la solución.
Rick James
8
Aparte, me gustaría hacer una pausa un momento y darle al equipo de MySQL una mirada realmente buena y dura. o_o WTF, ¿estaban pensando? ¿Se da cuenta de cuánta confusión sembró al crear una página de códigos en su programa llamada "utf8" que en realidad no es UTF-8? Malditos idiotas. </rant>
TWR Cole
20

La respuesta corta: Úselo utf8mb4en 4 lugares:

  • Los bytes en su cliente son utf8, no latin1 / cp1251 / etc.
  • SET NAMES utf8mb4 o algo equivalente al establecer la conexión del cliente a MySQL
  • CHARACTER SET utf8mb4 en todas las tablas / columnas, excepto las columnas que son estrictamente ascii / hex / country_code / zip_code / etc.
  • <meta charset charset=UTF-8>si está enviando a HTML. (Sí, la ortografía es diferente aquí).

Más info ;
UTF8 hasta el final

Los enlaces anteriores proporcionan la "respuesta canónica detallada se requiere para abordar todas las preocupaciones". - Hay un límite de espacio en este foro.

Editar

Además de CHARACTER SET utf8mb4contener "todos" los personajes del mundo, COLLATION utf8mb4_unicode_520_cies discutible la colación "mejor completa" que se puede utilizar. (También hay colaciones de turco, español, etc. para aquellos que quieren los matices en esos idiomas).

Rick James
fuente
Mi nuevo enlace sobre cómo depurar problemas de utf8 a partir de la salida que obtiene.
Rick James
Por qué unicode_520_ci no es el mejor de todos: stackoverflow.com/a/49982378/62202
Louis
@Louis - Y como he insinuado, los usuarios españoles y turcos (así como polacos) pueden no estar contentos. "Lo mejor en general" tiende a hacer daño a todos. MySQL 8.0 tiene una "mejor" colación aún más nueva: utf8mb4_0900_ai_ci . Por desgracia, de nuevo L = Ł.
Rick James
4

El juego de caracteres es una propiedad de la base de datos (predeterminado) y la tabla. Puedes echar un vistazo (comandos de MySQL):

show create database foo; 
> CREATE DATABASE  `foo`.`foo` /*!40100 DEFAULT CHARACTER SET latin1 */

show create table foo.bar;
> lots of stuff ending with
> ) ENGINE=InnoDB AUTO_INCREMENT=252 DEFAULT CHARSET=latin1

En otras palabras; es bastante fácil verificar el conjunto de caracteres de su base de datos o cambiarlo:

ALTER TABLE `foo`.`bar` CHARACTER SET utf8;
extraneón
fuente
1
Esto no es correcto. Lo que MySQL llama utf8no es UTF-8 "completo".
TWR Cole
2

Seguí la solución de Javier, pero agregué algunas líneas diferentes en my.cnf:

[myslqd]
skip-character-set-client-handshake
collation_server=utf8_unicode_ci
character_set_server=utf8 

Encontré esta idea aquí: http://dev.mysql.com/doc/refman/5.0/en/charset-server.html en el primer / único comentario del usuario en la parte inferior de la página. Menciona que saltar-juego-de-caracteres-cliente-apretón de manos tiene cierta importancia.

Vlad Balan
fuente
¡Esta respuesta sin amor y sin votos fue lo único que me ayudó! Así que obtiene mi voto, eso es seguro. skip-character-set-client-handshakefue la clave.
Marcus
0

Configure su database collationpara UTF-8 luego aplicar table collationa la base de datos predeterminada.

Chico Gaurav
fuente
-1

Su respuesta es que puede configurar mediante MySql Settings. En My Answer puede haber algo fuera de contexto, pero esto también es una ayuda para ti.
cómo configurar Character SetyCollation .

Para las aplicaciones que almacenan datos usando el juego de caracteres predeterminado de MySQL y la intercalación ( latin1, latin1_swedish_ci), no se necesita una configuración especial. Si las aplicaciones requieren el almacenamiento de datos con un juego de caracteres o una colación diferente, puede configurar la información del juego de caracteres de varias formas:

  • Especifique la configuración de caracteres por base de datos. Por ejemplo, las aplicaciones que usan una base de datos pueden requerir utf8, mientras que las aplicaciones que usan otra base de datos pueden requerir sjis.
  • Especifique la configuración de caracteres al iniciar el servidor. Esto hace que el servidor use la configuración dada para todas las aplicaciones que no hacen otros arreglos.
  • Especifique la configuración de caracteres en el momento de la configuración , si crea MySQL desde la fuente. Esto hace que el servidor use la configuración dada para todas las aplicaciones, sin tener que especificarlas al iniciar el servidor.

Los ejemplos que se muestran aquí para su pregunta para establecer el conjunto de caracteres utf8, aquí también establecen la intercalación para más útil ( utf8_general_ciintercalación`).

Especificar la configuración de caracteres por base de datos

  CREATE DATABASE new_db
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

Especificar la configuración de caracteres al iniciar el servidor

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

Especificar la configuración de caracteres en el momento de la configuración de MySQL

shell> cmake . -DDEFAULT_CHARSET=utf8 \
           -DDEFAULT_COLLATION=utf8_general_ci

Para ver los valores del conjunto de caracteres y las variables del sistema de clasificación que se aplican a su conexión, utilice estas declaraciones:

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

Esta puede ser una respuesta larga, pero puede usarla. Espero que mi respuesta te sea útil. para obtener más información http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html

Vipin Jain
fuente
-2

SET NAMES UTF8

Este es el truco

Claudio
fuente
2
Si bien el uso de SET NAMES UTF8(o UTF8mb4) es correcto, no explica qué hace (juego de caracteres utilizado para esta conexión). "Esto hace el truco" parece que resolvería el problema (hacer que MySQL maneje UTF-8 correctamente), pero muchas bases de datos MySQL están configuradas en latin1 por defecto, por lo que eso no lo convertiría en una solución adecuada. Me gustaría cambiar el juego de caracteres por defecto y los juegos de caracteres de la tabla a utf8mb4. Realmente, esta respuesta es bastante incompleta, así que la rechacé.
básico 6
-2

CONEXIÓN DE LA BASE DE DATOS A UTF-8

$connect = mysql_connect('$localhost','$username','$password') or die(mysql_error());
mysql_set_charset('utf8',$connect);
mysql_select_db('$database_name','$connect') or die(mysql_error());
sunil subramanya
fuente
-3

Establezca su conexión de base de datos en UTF8:

  if($handle = @mysql_connect(DB_HOST, DB_USER, DB_PASS)){          
         //set to utf8 encoding
         mysql_set_charset('utf8',$handle);
  }
aleta
fuente
Si está ejecutando PHP, no utilice la mysql_*interfaz obsoleta . Cambiar a mysqli_*o PDO.
Rick James
-3

Pude encontrar una solución. Ejecutó lo siguiente como se especifica en http://technoguider.com/2015/05/utf8-set-up-in-mysql/

SET NAMES UTF8;
set collation_server = utf8_general_ci;
set default-character-set = utf8;
set init_connect = SET NAMES utf8′;
set character_set_server = utf8;
set character_set_client = utf8;
Nishant
fuente
Las dos últimas líneas son redundantes, ya que el primero ya incluye a aquellos: dev.mysql.com/doc/refman/5.0/en/charset-connection.html
DanielM
Tampoco es una solución completa. Las columnas necesitan CHARACTER SET utf8. rootno ejecutará lo más importante init_connect.
Rick James