强制 MariaDB 客户端使用 utf8mb4

Posted

技术标签:

【中文标题】强制 MariaDB 客户端使用 utf8mb4【英文标题】:Force MariaDB clients to use utf8mb4 【发布时间】:2018-05-13 23:38:51 【问题描述】:

我遇到了一个问题,即在使用 php 与命令行进行查询时,我得到了不同的排序结果。根据我的研究,在某些情况下,错误的编码可能会导致结果顺序出现问题。

也就是说,我所有的数据库表都编码为utf8mb4,排序规则为utf8mb4_general_ci。但是,似乎mysql变量设置不正确。

我在 Mysql 5.5.5-10.1.26-MariaDb 上。

这是我的 CNF 设置,但老实说我不知道​​我在这里做什么:

[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mariadb]


[mysqld]

character-set-server=utf8mb4
character_set_client=utf8mb4
collation-server=utf8mb4_general_ci

mysql 输出的变量:

character_set_client        utf8
character_set_connection    utf8
character_set_database      utf8mb4
character_set_filesystem    binary
character_set_results       utf8
character_set_server        utf8mb4
character_set_system        utf8
collation_connection        utf8_general_ci
collation_database          utf8mb4_unicode_ci
collation_server            utf8mb4_general_ci

更新:有人询问我如何连接到数据库:

$this->connection = new PDO('mysql:host='.DB_SERVER.';dbname='.DB_NAME.';port='.DB_PORT, DB_USER, DB_PASS, $options);

更新:我已切换到utf8mb4_unicode_ci(根据以下答案中的建议)。

【问题讨论】:

请告诉我们您如何从 pup 连接到 mariadb 以及您使用的 API。 我不只是使用 PHP,我还使用其他语言。所以我宁愿不要在 PHP 本身中设置它。没有人应该控制改变这个......这表示我已经用该信息更新了问题。 他们确实可以控制设置字符集,因为不同的客户端可能使用不同的字符集和排序规则。 如果我需要为每个都设置它,这不是一个大问题。我只是想确保我在正确的轨道上考虑到编码混乱会导致问题一直出现。 见***.com/questions/4361459/php-pdo-charset-set-names 【参考方案1】:

要修复此警告,您应该编辑

/etc/my.cnf (my.ini on Windows)

只需在文件中添加/设置

[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqld]
collation-server=utf8mb4_unicode_ci
init-connect='SET NAMES utf8mb4'
character-set-server=utf8mb4

【讨论】:

【参考方案2】:

您也希望有 character-set-client-handshake = FALSE

/etc/my.cnf.d/character-set.cnf

# https://scottlinux.com/2017/03/04/mysql-mariadb-set-character-set-and-collation-to-utf8/
# https://mariadb.com/kb/en/library/setting-character-sets-and-collations/
# https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434
# https://***.com/questions/47566730/force-mariadb-clients-to-use-utf8mb4

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-client-handshake = FALSE
collation-server = utf8mb4_unicode_ci
init-connect = 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci'
character-set-server = utf8mb4

我得到的一切都是 utf8mb41

MariaDB [(none)]> show variables like 'char%'; show variables like 'collation%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

+----------------------+--------------------+
| Variable_name        | Value              |
+----------------------+--------------------+
| collation_connection | utf8mb4_unicode_ci |
| collation_database   | utf8mb4_unicode_ci |
| collation_server     | utf8mb4_unicode_ci |
+----------------------+--------------------+
3 rows in set (0.00 sec)

MariaDB [(none)]>

但是,如果没有 character-set-client-handshake 行,有些仍然是 utf8

MariaDB [(none)]> show variables like 'char%'; show variables like 'collation%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

+----------------------+--------------------+
| Variable_name        | Value              |
+----------------------+--------------------+
| collation_connection | utf8_general_ci    |
| collation_database   | utf8mb4_unicode_ci |
| collation_server     | utf8mb4_unicode_ci |
+----------------------+--------------------+
3 rows in set (0.01 sec)

MariaDB [(none)]>

1 character_set_system 是always utf8。

【讨论】:

【参考方案3】:

init_connect 不是由以root 连接的任何人执行的,因此它不像您希望的那样通用。

SET NAMES utf8mb4 设置 3 个东西;实验看看。你需要全部 3 个。

如果您不早于 5.5,我会推荐 utf8mb4_unicode_520_ci 作为更好的排序规则:“Unicode 排序规则名称现在可能包含一个版本号,以指示排序规则所基于的 Unicode 排序算法 (UCA) 版本是基于的。因此创建的初始排序规则使用版本 UCA 5.2.0。例如,utf8_unicode_520_ci 基于 UCA 5.2.0。不包含版本号的基于 UCA 的 Unicode 排序规则名称基于版本 4.0.0。"

8.0 版具有 Unicode 9.0 标准。

回到问题:没有完美的解决方案;用户可以通过无知或恶意覆盖您所做的任何事情。

可以监管创建的表,但这不会阻止它们错误地连接。或者正确,但使用不同的字符集。执行SET NAMES latin1有效,然后提供 latin1-encode 字节。 MySQL 将在存储/获取时进行转换。

但是如果它们有 utf8 编码的字节,但是说 SET NAMES latin1,你会得到“双重编码”。这个“错误”破坏了任何正确整理的机会,但在其他方面(通常)是透明的。也就是说,东西在存储时被弄乱了,然后在提取时被弄乱了。

【讨论】:

【参考方案4】:

您应该可能使用 utf8mb4_unicode_ci 而不是 utf8mb4_general_ci,因为它更准确。除非您在具有旧/有限 CPU 的系统上运行 MariaDB,否则性能是一个巨大的问题。

话虽如此,解决方案是在您的 MariaDB 配置中设置 init_connect(或在命令行中设置 --init-connect):

init_connect = "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"

无论哪种方式都可以。我不推荐一种方法而不是另一种方法。两者都是同样有效的方法。

您的 MariaDB 配置可能位于 my.cnf 或 my.cnf 包含的文件中,通常位于 /etc/mysql 下。检查您的系统文档以了解详细信息。因为您正在配置服务器变量,如上面链接的 MariaDB 文档所示,您应该在配置文件的服务器部分设置变量。配置文件的服务器部分由以“d”结尾的 INI 部分名称表示。 INI 部分由方括号括起来的关键字表示,例如“[部分]”。 “d”代表“daemon”,它是服务器进程的标准 UNIX 命名法。您可以在[mysqld] 部分或[mariadb] 部分中设置变量。因为init_connect 服务器变量对 MySQL 和 MariaDB 来说都是通用的,所以我建议你把它放在[mysqld] 下。

我看到您在粘贴的配置中设置了character_set_client=utf8mb4。你不需要这样做。您可以删除或注释掉该行。注释是以磅符号 (#) 开头的行,也称为井号、八角或数字符号。

任何和所有连接到服务器的客户端都将在处理任何其他命令之前执行这些命令。

【讨论】:

使用utf8mb4_unicode_ci而不是utf8mb4_general_ci的原因是什么?将其放入您的答案中会有所帮助。另外,您是否建议不要使用 my.cnf 文件,为什么? 更准确。我会修改我的答案来这么说。不……我不知道你为什么认为我这么建议。 我现在明白了,您是说将那行放在 my.cnf 中,但那行是否与其他行一起使用?我需要其他线路吗? 是的,在[mysqld](或[mariadb])下,是的,你需要它们,但你不需要设置character_set_client 这不会影响从 php 建立的连接,它们会覆盖这个设置。

以上是关于强制 MariaDB 客户端使用 utf8mb4的主要内容,如果未能解决你的问题,请参考以下文章

mariadb设置utf8mb4

带有动态列和过程的 mariadb utf8mb4

mariadb设置utf8mb4

UTF8mb4 unicode 破坏 MariaDB JDBC 驱动程序

如何使用 to_sql 对表创建强制执行 utf8mb4?

mysql选择字符集utf8mb4