一尘不染

是否需要“ SET CHARACTER SET utf8”?

mysql

我重新编写了我们的数据库类(基于PDO),并陷入了困境。我被教导如何在PHP和MySQL中使用SET NAMES utf8以及SET CHARACTER SET utf8在UTF-8中使用。

在PDO中,我现在想使用PDO::MYSQL_ATTR_INIT_COMMAND参数,但它仅支持一个查询。

SET CHARACTER SET utf8必要吗?


阅读 665

收藏
2020-05-17

共1个答案

一尘不染

利用SET CHARACTER SET utf8使用后SET NAMES utf8实际上会重置character_set_connection,并collation_connection
@@character_set_database@@collation_database分别。

手册指出

  • SET NAMES x 相当于

    SET character_set_client = x;
    

    SET character_set_results = x;
    SET character_set_connection = x;

  • SET CHARACTER SET x相当于

    SET character_set_client = x;
    

    SET character_set_results = x;
    SET collation_connection = @@collation_database;

SET collation_connection = x同时在内部执行SET character_set_connection = <<character_set_of_collation_x>>SET character_set_connection = x内部还执行SET collation_connection = <<default_collation_of_character_set_x

所以基本上你重新character_set_connection@@character_set_databasecollation_connection@@collation_database。手册说明了这些变量的用法:

服务器在收到语句后应将其转换为什么字符集?

为此,服务器使用character_set_connection和collat​​ion_connection系统变量。它将客户端发送的语句从character_set_client转换为character_set_connection(具有诸如_latin1或_utf8之类的介绍符的字符串文字除外)。collat​​ion_connection对于比较文字字符串很重要。对于将字符串与列值进行比较,collat​​ion_connection无关紧要,因为列具有自己的排序规则,排序规则优先级更高。

综上所述,MySQL用于处理查询的编码/代码转换过程及其结果是一个多步骤的过程:

  1. MySQL将传入查询视为编码character_set_client
  2. MySQL将语句从character_set_client转换为character_set_connection
  3. 当比较字符串值和列值时,MySQL将字符串值从转码character_set_connection到给定数据库列的字符集中,并使用列排序规则进行排序和比较。
  4. MySQL建立编码的结果集character_set_results(其中包括结果数据以及结果元数据,例如列名等)

因此,可能情况是a SET CHARACTER SET utf8不足以提供完整的UTF-8支持。考虑latin1使用utf8-charset
定义的和的默认数据库字符集和列,并执行上述步骤。由于latin1无法覆盖UTF-8可以覆盖的所有字符,因此在步骤 3中 可能会丢失字符信息。

  • 3 步:假设您的查询是使用UTF-8编码的,并且包含无法用表示的字符,则latin1这些字符将在从utf8latin1(默认数据库字符集)的转码时丢失,从而使查询失败。

因此,我认为可以肯定地说这SET NAMES ...是处理字符集问题的正确方法。即使我可能会补充说,正确设置MySQL服务器变量(所有必需的变量都可以在中静态设置my.cnf)可以使您免除每次连接所需的额外查询的性能开销。

2020-05-17