如何使MySQL正确处理UTF-8


102

昨天我一个问题的回答之一是建议我确保我的数据库可以正确处理UTF-8字符。如何使用MySQL做到这一点?


4
我真的很希望我们得到了一个全面的答案,涵盖了各个版本的MySQL,不兼容等
爱德华Z.杨


1
@ EdwardZ.Yang-MySQL 4.1引入CHARACTER SETs; 5.1.24弄乱了德国Sharp-s(ß)的排序规则,该规则已在5.1.62中添加另一个排序规则进行了纠正(可以说使情况更糟);5.5.3用新的字符集utf8mb4填充utf8。
瑞克·詹姆斯

1
这个问题是不太一样这一个。请看看这stackoverflow.com/questions/3513773/...
Nyein昂

值得指出的是,大多数答案都是错误的。不要使用utf8。它仅支持3个字节的字符。您应该在MySQL中使用的正确字符集是utf8mb4
布兰丹·伯德

Answers:


89

更新:

简短答案-您几乎应该始终使用utf8mb4字符集和utf8mb4_unicode_ci排序规则。

更改数据库:

ALTER DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

看到:

原始答案:

MySQL 4.1及更高版本具有默认字符集UTF-8。您可以在验证这个my.cnf文件,记得设置两个客户端和服务器(default-character-setcharacter-set-server)。

如果您希望将现有数据转换为UTF-8,请转储数据库,然后将其作为UTF-8导入,确保:

  • SET NAMES utf8在查询/插入数据库之前使用
  • DEFAULT CHARSET=utf8在创建新表时使用
  • 此时,您的MySQL客户端和服务器应位于UTF-8中(请参阅参考资料my.cnf)。请记住,您使用的任何语言(例如PHP)也必须是UTF-8。某些版本的PHP将使用他们自己的MySQL客户端库,该客户端库可能不支持UTF-8。

如果要迁移现有数据,请记住先备份!当事情没有按计划进行时,可能会发生很多奇怪的数据砍伐事件!

一些资源:


29
我的理解是,utf8MySQL内仅指完整Unicode的一小部分。您应该改用utf8mb4强制全面支持。参见mathiasbynens.be/notes/mysql-utf8mb4 “很长一段时间以来,我一直在将MySQL的utf8字符集用于数据库,表和列,并假定它映射到上述的UTF-8编码。”
亚伦·麦克戴德2013年

7
MySQL从来没有默认的字符集UTF-8。4.1和5.x到最新的5.7都使用,latin1并且latin1_swedish_ci用于默认字符集和排序规则。请参见MySQL手册中的“服务器字符集和排序规则”页面以进行确认:dev.mysql.com/doc/refman/5.1/en/charset-server.html
Animism 2014年

2
@TimTisdall utf8mb4当大多数文本为ASCII时,您不必担心会占用额外的存储空间。尽管char字符串是预先分配的,但varchar字符串不是-请参阅本文档页面的最后几行。例如,char(10)将在utf8mb4下悲观地保留40个字节,但varchar(10)将分配与可变长度编码保持一致的字节。
Kevin A.Naudé2014年

1
@Kevin我想​​你误读了。我认为最大行长度是64k。您只能将utf8mb4字段设为该字段的1/4,因为它必须保留该空间量。因此,即使是ASCII,您也只能插入16k个字符。
Tim Tisdall 2014年

1
@TimTisdall哦,您是在谈论上限。是的,这些较低。幸运的是,MySQL的当前版本将自动升级varchar(n)text数据类型,如果你试图改变varchar(n)字段设置为大于可行的字节大小(同时发出警告)。索引还将具有最坏情况下限的下限,并且可能会带来其他问题。
Kevin A.Naudé2014年

44

为了使这个“永久”,在my.cnf

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

要进行检查,请转到客户端并显示一些变量:

SHOW VARIABLES LIKE 'character_set%';

验证它们全部为utf8,除了..._filesystem,应该为binary..._dir,它们指向MySQL安装中的某个位置。


在我的情况下,它不起作用,但是我还是在/ etc中使用给定的内容创建了文件my.cf。我用过create table my_name(field_name varchar(25) character set utf8);
Marek Bar

“显示变量,例如'character_set%';” 命令向我显示了我的连接问题。谢谢!
javsmo 2015年

1
这是不正确的。MySQL所说utf8的不是“完整的” UTF-8。
TWR Cole

32

MySQL 4.1及更高版本具有调用的默认字符集,utf8但实际上仅是UTF-8的子集(仅允许使用三字节字符或更小字符)。

utf8mb4如果要“完整” UTF-8,请用作字符集。


5
绝对同意,这是唯一正确的答案。utf8不包括像表情符号这样的字符。utf8mb4做。检查此内容以获取有关如何更新的更多信息:mathiasbynens.be/notes/mysql-utf8mb4
jibai31 2015年

@Basti-大多是正确的(latin1是直到最近的默认值),并且还不完整(没有讨论正确插入/选择utf8编码的数据,也没有以html显示)。
瑞克·詹姆斯

@ RickJames,Basti表示敬意,“到目前为止”-当我发布此信息时,我不记得看到您的回答。
TWR Cole

las,utf8问题大约有5种明显不同的症状,而程序员为错误而做错的大约4件事。大多数答案仅指出可能需要修复的件事。最初的问题很笼统,所以答案全部都是4。也许Basti熟悉一种症状,而您的一方面就是解决方案。
瑞克·詹姆斯

8
顺便说一句,我想休息片刻,并给MySQL团队一个非常好的,凝视的东西。你们在想WTF吗?通过在程序中创建一个实际上不是UTF-8的代码页“ utf8”,您是否意识到自己已经造成了多少混乱?该死的混蛋。</ rant>
TWR Cole

20

简短的答案:utf8mb4在4个地方使用:

  • 客户端中的字节是utf8,而不是latin1 / cp1251 / etc。
  • SET NAMES utf8mb4 建立客户端与MySQL的连接时的等效命令
  • CHARACTER SET utf8mb4 在所有表/列上-严格按ascii / hex / country_code / zip_code / etc的列除外。
  • <meta charset charset=UTF-8>如果要输出为HTML。(是的,这里的拼写不同。)

更多信息 ;
一路UTF8

上面的链接提供了“解决所有问题都需要详细的规范答案”。-此论坛有空间限制。

编辑

除了CHARACTER SET utf8mb4包含“所有”世界字符之外,COLLATION utf8mb4_unicode_520_ci可以说是使用的“最佳全方位”排序规则。(也有土耳其语,西班牙语等排序规则,供那些希望使用这些语言的细微差别的人使用。)


我关于如何从输出中调试utf8问题的新链接
瑞克·詹姆斯

为什么unicode_520_ci并不是最好的方法:stackoverflow.com/a/49982378/62202
路易(Louis)

@Louis-正如我所暗示的,西班牙语和土耳其语(以及波兰语)的用户可能不满意。“全能最佳”往往会伤害所有人。MySQL 8.0具有甚至更高的“最佳”排序规则:utf8mb4_0900_ai_ci。las,L =Ł。
瑞克·詹姆斯

4

字符集是数据库(默认)和表的属性。您可以看一下(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

换一种说法; 检查或更改数据库字符集非常容易:

ALTER TABLE `foo`.`bar` CHARACTER SET utf8;

1
这是不正确的。MySQL所说utf8的不是“完整的” UTF-8。
TWR Cole


2

我遵循了哈维尔的解决方案,但在my.cnf中添加了一些不同的行:

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

我在这里找到了这个想法:http : //dev.mysql.com/doc/refman/5.0/en/charset-server.html在页面底部的第一个/唯一用户注释中。他提到跳过字符集客户端握手非常重要。


唯一没有帮助的零投票答案是对我唯一的帮助!所以这是我的投票,这是肯定的。 skip-character-set-client-handshake是关键。
马库斯


0

设置database collation为,UTF-8 然后将其应用于table collation数据库默认值。


-1

您的答案是可以通过MySql设置进行配置。在“我的答案”中可能是脱离上下文的,但这也知道对您有帮助。
如何配置Character SetCollation

对于使用默认MySQL字符集和排序规则(latin1, latin1_swedish_ci)存储数据的应用程序,不需要特殊配置。如果应用程序要求使用其他字符集或排序规则存储数据,则可以通过以下几种方式配置字符集信息:

  • 指定每个数据库的字符设置。例如,使用一个数据库的应用程序可能需要utf8,而使用另一个数据库的应用程序可能需要sji。
  • 在服务器启动时指定字符设置。这导致服务器将给定的设置用于所有未进行其他安排的应用程序。
  • 如果您从源代码构建MySQL,请在配置时指定字符设置。这将导致服务器对所有应用程序使用给定的设置,而不必在服务器启动时指定它们。

此处显示的示例用于您设置utf8字符集的问题,此处还设置了归类以提供更多帮助(utf8_general_cicollat​​ion`)。

指定每个数据库的字符设置

  CREATE DATABASE new_db
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

在服务器启动时指定字符设置

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

在MySQL配置时指定字符设置

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

要查看适用于您的连接的字符集和排序规则系统变量的值,请使用以下语句:

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

这可能是一个冗长的答案,但是可以使用所有方法。希望我的回答对您有所帮助。有关更多信息,请访问http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html


-2

SET NAMES UTF8

这就是窍门


2
虽然使用SET NAMES UTF8(或UTF8mb4)是正确的,但您无需解释它的作用(用于此连接的字符集)。听起来“解决了这个问题”似乎可以解决问题(使MySQL正确处理UTF-8),但是默认情况下,许多MySQL数据库默认设置为latin1,因此这并不是一个合适的解决方案。我将默认字符集和表字符集更改为utf8mb4。确实,这个答案还算不完整,因此我拒绝了。
basic6 2014年

-2

与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());

-3

将数据库连接设置为UTF8:

  if($handle = @mysql_connect(DB_HOST, DB_USER, DB_PASS)){          
         //set to utf8 encoding
         mysql_set_charset('utf8',$handle);
  }

如果运行PHP,请不要使用不建议使用的mysql_*接口。切换到mysqli_*PDO
瑞克·詹姆斯

-3

能够找到解决方案。按照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;

最后两行是多余的,因为第一个已经包括的那些:dev.mysql.com/doc/refman/5.0/en/charset-connection.html
DanielM

也不是一个完整的解决方案。列需要CHARACTER SET utf8root不会执行all-important init_connect
瑞克·詹姆斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.