Como fazer o MySQL lidar com UTF-8 corretamente

102

Uma das respostas a uma pergunta que fiz ontem sugeriu que eu deveria ter certeza de que meu banco de dados pode lidar com caracteres UTF-8 corretamente. Como posso fazer isso com o MySQL?

Ben
fonte
4
Eu realmente espero que recebamos uma resposta abrangente, cobrindo várias versões do MySQL, incompatibilidades, etc.
Edward Z. Yang
1
@ EdwardZ.Yang - MySQL 4.1 introduzido CHARACTER SETs; 5.1.24 mexeu com o agrupamento do alemão sharp-s (ß), que foi retificado pela adição de outro agrupamento em 5.1.62 (possivelmente tornando as coisas piores); 5.5.3 preenchido utf8 com o novo charset utf8mb4.
Rick James
1
Esta pergunta é quase igual a esta .. Por favor, olhe stackoverflow.com/questions/3513773/…
Nyein Aung
Vale a pena ressaltar que a maioria dessas respostas está simplesmente errada. Não use utf8. Ele suporta apenas caracteres de até 3 bytes. O conjunto de caracteres correto que você deve usar no MySQL é utf8mb4.
Brendan Byrd

Respostas:

89

Atualizar:

Resposta curta - você quase sempre deve usar o conjunto de utf8mb4caracteres e o utf8mb4_unicode_ciagrupamento.

Para alterar o banco de dados:

ALTER DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Vejo:

Resposta Original:

O MySQL 4.1 e superior tem um conjunto de caracteres padrão UTF-8. Você pode verificar isso em seu my.cnfarquivo, lembre-se de definir o cliente e o servidor ( default-character-sete character-set-server).

Se você tiver dados que deseja converter para UTF-8, descarte seu banco de dados e importe-o de volta como UTF-8 certificando-se de:

  • use SET NAMES utf8antes de consultar / inserir no banco de dados
  • usar DEFAULT CHARSET=utf8ao criar novas tabelas
  • neste ponto, seu cliente e servidor MySQL devem estar em UTF-8 (consulte Recursos my.cnf). lembre-se de que todas as linguagens que você usa (como PHP) também devem ser UTF-8. Algumas versões do PHP usarão sua própria biblioteca cliente MySQL, que pode não ser compatível com UTF-8.

Se você deseja migrar os dados existentes, lembre-se de fazer o backup primeiro! Muitos dados estranhos podem acontecer quando as coisas não saem como planejado!

Alguns recursos:

Owen
fonte
29
Meu entendimento é que utf8no MySQL se refere apenas a um pequeno subconjunto do Unicode completo. Você deve usar em utf8mb4vez disso para forçar o suporte total. Consulte mathiasbynens.be/notes/mysql-utf8mb4 "Por muito tempo, usei o conjunto de caracteres utf8 do MySQL para bancos de dados, tabelas e colunas, supondo que fosse mapeado para a codificação UTF-8 descrita acima."
Aaron McDaid
7
O MySQL nunca teve um conjunto de caracteres padrão UTF-8. 4.1 e 5.x até o 5.7 mais recente, todos usam latin1e latin1_swedish_cipara o conjunto de caracteres e agrupamento padrão. Veja o "caráter Servidor Set e Agrupamento" página no manual do MySQL para confirmação: dev.mysql.com/doc/refman/5.1/en/charset-server.html
Animismo
2
@TimTisdall Você não precisa se preocupar em utf8mb4ocupar espaço extra quando a maior parte do texto é ASCII. Embora charstrings sejam pré-alocadas, varcharstrings não são - veja as últimas linhas nesta página de documentação . Por exemplo, char(10)será pessimisticamente reservar 40 bytes em utf8mb4, mas varchar(10)irá alocar bytes de acordo com a codificação de comprimento variável.
Kevin A. Naudé
1
@Kevin Eu acho que você interpretou mal isso. Acho que o comprimento máximo da linha é 64k. Você só pode fazer um campo utf8mb4 1/4 disso porque ele teve que reservar essa quantidade de espaço. Portanto, mesmo que seja ASCII, você só pode inserir 16k caracteres.
Tim Tisdall,
1
@TimTisdall Oh, você está falando sobre limites superiores. Sim, esses são mais baixos. Felizmente, as versões atuais do mysql irão atualizar automaticamente varchar(n)para o texttipo de dados se você tentar alterar um varchar(n)campo para um tamanho maior do que o byte viável (ao emitir um aviso). Um índice também terá um limite superior inferior de pior caso, e isso pode apresentar outros problemas.
Kevin A. Naudé
44

Para tornar isso 'permanente', em my.cnf:

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

Para verificar, vá até o cliente e mostre algumas variáveis:

SHOW VARIABLES LIKE 'character_set%';

Verifique se eles são todos utf8, exceto o ..._filesystemque deve ser binarye ..._dir, que aponta para algum lugar na instalação do MySQL.

Javier
fonte
Não funcionou no meu caso, mas criei o arquivo my.cf em / etc com o conteúdo fornecido de qualquer maneira. Eu useicreate table my_name(field_name varchar(25) character set utf8);
Marek Bar
O "SHOW VARIABLES LIKE 'character_set%';" comando me revelou o problema com minha conexão. Obrigado!
javsmo
1
Isso não está correto. O que o MySQL chama utf8não é UTF-8 "completo".
TWR Cole
32

O MySQL 4.1 e superior tem um conjunto de caracteres padrão que ele chama, utf8mas que na verdade é apenas um subconjunto de UTF-8 (permite apenas caracteres de três bytes e menores).

Use utf8mb4como seu conjunto de caracteres se desejar UTF-8 "completo".

TWR Cole
fonte
5
Concordo, esta é a única resposta correta. utf8não inclui caracteres como emoticons. utf8mb4faz. Verifique isso para obter mais informações sobre como atualizar: mathiasbynens.be/notes/mysql-utf8mb4
jibai31
@Basti - Principalmente correto (latin1 era o padrão até recentemente), e não completo (não discute a inserção / seleção correta de dados codificados em utf8, nem a exibição em html).
Rick James
Respeitosamente, @RickJames, Basti disse "até agora" - não me lembro de ter visto sua resposta quando postei isto.
TWR Cole
Infelizmente, existem cerca de 5 sintomas distintos de problemas de utf8 e cerca de 4 coisas que os programadores fazem de errado para causar problemas. A maioria das respostas aponta apenas uma coisa que pode precisar de conserto. A pergunta original era ampla, então a resposta precisava de todos os 4. Talvez Basti estivesse familiarizado com um sintoma para o qual seu único aspecto era a solução.
Rick James
8
Como um aparte, gostaria de fazer uma pausa e dar à equipe MySQL um olhar realmente bom e duro. o_o WTF vocês estavam pensando? Você percebe quanta confusão semeou ao criar uma página de código em seu programa chamada "utf8" que não é realmente UTF-8? Idiotas malditos. </rant>
TWR Cole
20

A resposta curta: Use utf8mb4em 4 lugares:

  • Os bytes em seu cliente são utf8, não latin1 / cp1251 / etc.
  • SET NAMES utf8mb4 ou algo equivalente ao estabelecer a conexão do cliente ao MySQL
  • CHARACTER SET utf8mb4 em todas as tabelas / colunas - exceto colunas estritamente ascii / hex / country_code / zip_code / etc.
  • <meta charset charset=UTF-8>se você estiver enviando para HTML. (Sim, a grafia é diferente aqui.)

Mais informações ;
UTF8 até o fim

Os links acima fornecem a "resposta canônica detalhada necessária para resolver todas as questões". - Existe um limite de espaço neste fórum.

Editar

Além de CHARACTER SET utf8mb4conter "todos" os personagens do mundo, COLLATION utf8mb4_unicode_520_cié discutível o agrupamento "melhor versátil" para usar. (Existem também agrupamentos turco, espanhol, etc., para quem deseja as nuances nesses idiomas.)

Rick James
fonte
Meu novo link sobre como depurar problemas do utf8 a partir da saída que você obtém.
Rick James
Por que unicode_520_ci não é o melhor: stackoverflow.com/a/49982378/62202
Louis
@Louis - E como eu sugeri, os usuários espanhóis e turcos (assim como poloneses) podem não gostar. "Melhor em todos os aspectos" tende a prejudicar um pouco a todos. O MySQL 8.0 tem um agrupamento "melhor" ainda mais recente: utf8mb4_0900_ai_ci . Infelizmente, novamente L = Ł.
Rick James de
4

O conjunto de caracteres é uma propriedade do banco de dados (padrão) e da tabela. Você pode dar uma olhada (comandos 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

Em outras palavras; é muito fácil verificar o conjunto de caracteres do seu banco de dados ou alterá-lo:

ALTER TABLE `foo`.`bar` CHARACTER SET utf8;
extrânon
fonte
1
Isso não está correto. O que o MySQL chama utf8não é UTF-8 "completo".
TWR Cole
2

Segui a solução de Javier, mas adicionei algumas linhas diferentes em my.cnf:

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

Eu encontrei essa ideia aqui: http://dev.mysql.com/doc/refman/5.0/en/charset-server.html no primeiro / único comentário do usuário na parte inferior da página. Ele menciona que o handshake skip-character-set-client-client tem alguma importância.

Vlad Balan
fonte
Essa resposta mal-amada e sem votos foi a única coisa que me ajudou! Então, tem meu voto, com certeza. skip-character-set-client-handshakefoi a chave.
Marcus de
0

Essas dicas sobre MySQL e UTF-8 podem ser úteis. Infelizmente, eles não constituem uma solução completa, apenas pegadinhas comuns.

Edward Z. Yang
fonte
0

Defina seu database collationpara, em UTF-8 seguida, aplique table collationao padrão do banco de dados.

Gaurav Lad
fonte
-1

Sua resposta é que você pode configurar por MySql Settings. Em Minha Resposta pode haver algo fora do contexto, mas isso também é uma ajuda para você.
como configurar Character SeteCollation .

Para aplicativos que armazenam dados usando o conjunto de caracteres MySQL padrão e collation ( latin1, latin1_swedish_ci), nenhuma configuração especial deve ser necessária. Se os aplicativos exigem armazenamento de dados usando um conjunto de caracteres ou agrupamento diferente, você pode configurar as informações do conjunto de caracteres de várias maneiras:

  • Especifique as configurações de caracteres por banco de dados. Por exemplo, os aplicativos que usam um banco de dados podem exigir utf8, enquanto os aplicativos que usam outro banco de dados podem exigir sjis.
  • Especifique as configurações de caracteres na inicialização do servidor. Isso faz com que o servidor use as configurações fornecidas para todos os aplicativos que não fazem outros arranjos.
  • Especifique as configurações de caracteres no momento da configuração , se você construir o MySQL a partir da fonte. Isso faz com que o servidor use as configurações fornecidas para todos os aplicativos, sem ter que especificá-las na inicialização do servidor.

Os exemplos mostrados aqui para sua pergunta definir conjunto de caracteres utf8, aqui também definir agrupamento para mais útil ( utf8_general_ciagrupamento`).

Especifique as configurações de caracteres por banco de dados

  CREATE DATABASE new_db
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

Especifique as configurações de caractere na inicialização do servidor

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

Especifique as configurações de caracteres no momento da configuração do MySQL

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

Para ver os valores do conjunto de caracteres e das variáveis ​​do sistema de agrupamento que se aplicam à sua conexão, use estas instruções:

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

Esta pode ser uma resposta demorada, mas há todas as maneiras que você pode usar. Espero que minha resposta seja útil para você. para obter mais informações http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html

Vipin Jain
fonte
-2

SET NAMES UTF8

Isso resolve o problema

Claudio
fonte
2
Embora o uso de SET NAMES UTF8(ou UTF8mb4) esteja correto, você não explica o que ele faz (conjunto de caracteres usado para esta conexão). "Isso resolve" parece que resolveria o problema (fazer o MySQL lidar com UTF-8 corretamente), mas muitos bancos de dados MySQL são configurados para latin1 por padrão, de modo que não seria uma solução adequada. Eu mudaria o conjunto de caracteres padrão e os conjuntos de caracteres da tabela para utf8mb4. Realmente, esta resposta está um tanto incompleta, então eu votei contra ela.
básico 6 de
-2

CONEXÃO DA BASE DE DADOS COM 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
fonte
-3

Defina sua conexão de banco de dados para UTF8:

  if($handle = @mysql_connect(DB_HOST, DB_USER, DB_PASS)){          
         //set to utf8 encoding
         mysql_set_charset('utf8',$handle);
  }
barbatana
fonte
Se estiver executando o PHP, não use a mysql_*interface obsoleta . Mude para mysqli_*ou PDO.
Rick James de
-3

Consegui encontrar uma solução. Executou o seguinte conforme especificado em 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
fonte
As duas últimas linhas são redundantes, pois a primeira já inclui aquelas: dev.mysql.com/doc/refman/5.0/en/charset-connection.html
DanielM
Também não é uma solução completa. As colunas precisam CHARACTER SET utf8. rootnão executará o mais importante init_connect.
Rick James de