我遇到了一个问题,当我使用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
(根据以下答案中的建议)。
答案 0 :(得分:3)
您还希望具有 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://stackoverflow.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
我得到的一切都是utf8mb4 1
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)]>
但是,如果没有字符集客户端握手行,有些仍然是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 字符集系统是always utf8。
答案 1 :(得分:1)
你应该可能使用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”代表“守护进程”,它是服务器进程的标准UNIX术语。您可以在[mysqld]
部分或[mariadb]
部分设置变量。因为init_connect
服务器变量对MySQL和MariaDB都是通用的,所以我建议你把它放在[mysqld]
下。
我发现您在粘贴的配置中设置了character_set_client=utf8mb4
。你不需要这样做。您可以删除或注释掉该行。注释是以井号(#
)开头的行,也称为井号,octothorp或数字符号。
连接到服务器的任何和所有客户端都将在处理任何其他命令之前执行这些命令。
答案 2 :(得分:1)
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
,则会得到“双重编码”。这个“bug”会破坏任何正确整理的机会,但除此之外(通常)是透明的。也就是说,东西在存储时会搞砸,然后在取出时搞乱。
答案 3 :(得分: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