MySQL 字符集:连接字符集和排序规则
关于
“连接”是 Client 端程序在连接到服务器时开始与服务器交互的会话的过程。Client 端通过会话连接发送 SQL 语句,例如查询。服务器通过连接将响应(例如结果集或错误消息)发送回 Client 端。
连接字符集和排序规则的系统变量
几个字符集和排序规则的系统变量与 Client 端与服务器的交互有关。其中一些已在前面的部分中提到:
- “character_set_server”和“collation_server”系统变量指示服务器字符集和排序规则。
- “character_set_database”和“collation_database”系统变量指示默认数据库的字符集和排序规则。
- 在处理 Client 端和服务器之间的连接通信时,还涉及其他字符集和排序规则系统变量。每个 Client 端都有特定于会话的与连接有关的字符集和排序规则系统变量。这些会话系统变量值在连接时初始化,但可以在会话中更改。
关于 Client 端连接的字符集和排序规则处理的几个问题:
- 语句离开 Client 时使用什么字符集?
- 服务器将“character_set_client”系统变量作为字符集,Client 端在其中发送语句。【某些字符集不能用作 Client 端字符集】
- 服务器在收到语句后应将其转换为什么字符集?
- 为了确定这一点,服务器使用“character_set_connection”和“collation_connection”系统变量:
- 服务器将 Client 端发送的语句从“character_set_client”转换为“character_set_connection”。例外:对于具有 _utf8mb4 或 _latin2 之类的介绍词的字符串常量,导引器确定字符集。
- “collation_connection”对于比较常量字符串很重要。对于具有列值的字符串比较,“collation_connection”无关紧要,因为列具有自己的排序规则,排序规则优先级更高。
- 在将查询结果发送回 Client 端之前,服务器应将其转换为什么字符集?
- 服务器将查询结果以“character_set_results”系统变量表示返回给 Client 端的字符集。这包括结果数据(例如列值),结果元数据(例如列名)和错误消息。
- 要告诉服务器不执行结果集或错误消息的转换,请将character_set_results设置为NULL或binary:
SET character_set_results = NULL; SET character_set_results = binary;
- 查看适用于当前会话的字符集和排序规则系统变量的值,请使用以下语句:
SELECT * FROM performance_schema.session_variables WHERE VARIABLE_NAME IN ( 'character_set_client', 'character_set_connection', 'character_set_results', 'collation_connection' ) ORDER BY VARIABLE_NAME;
- 以下更简单的语句还显示连接变量,但也包括其他相关变量。它们对于查看all字符集和排序规则系统变量很有用:
SHOW SESSION VARIABLES LIKE 'character\_set\_%'; SHOW SESSION VARIABLES LIKE 'collation\_%'; Client 端可以微调这些变量的设置,或者取决于默认值(在这种情况下,您可以跳过本节的其余部分)。如果不使用默认值,则必须更改与服务器的每个连接的字符设置。
不允许的 Client 字符集
“character_set_client”系统变量不能设置为某些字符集:
ucs2
utf16
utf16le
utf32
尝试将任何这些字符集用作 Client 端字符集都会产生错误:
mysql> SET character_set_client = 'ucs2';
ERROR 1231 (42000): Variable 'character_set_client'
can't be set to the value of 'ucs2'
如果在以下上下文中使用了任何这些字符集,则会发生相同的错误,所有这些都导致尝试将“character_set_client”设置为命名字符集:【???】
- MySQLClient 端程序(例如mysql和mysqladmin)使用的“--default-character-set=charset_name”命令选项。
- “SET NAMES 'charset_name'”语句。
- “SET CHARACTER SET 'charset_name'”语句。
Client 端程序连接字符集配置
当 Client 端连接到服务器时,它表明它要用于与服务器通信的字符集。(实际上,Client 端表明该字符集的默认排序规则,服务器就可以从中确定字符集)。服务器使用此信息将“character_set_client”,“character_set_results”,“character_set_connection”系统变量设置为字符集,并将“collation_connection”设置为字符设置默认排序规则。实际上,服务器执行等效于“SET NAMES”的操作。
- 如果服务器不支持所请求的字符集或排序规则,它会退回到使用服务器字符集和排序规则来配置连接。
mysql,mysqladmin,mysqlcheck,mysqlimport 和 mysqlshow 等 Client 端程序确定要使用的默认字符集:
- 在没有其他信息的情况下,每个 Client 端都使用内置的默认字符集,通常为 latin1。
- 每个 Client 端都可以基于 os 设置自动检测要使用的字符集,(例如 Unix 系统上的 LANG 或 LC_ALL 语言环境变量的值,或 Windows 系统上的代码页设置)。对于从 OS 可以在其上使用语言环境的系统,Client 端使用它来设置默认字符集,而不是使用已编译的默认字符集。例如,将 LANG 设置为 ru_RU.KOI8-R 会导致使用 koi8r 字符集。因此,用户可以在其环境中配置区域设置,以供 MySQLClient 端使用。
- 如果没有完全匹配,则 OS 字符集将映射到最接近的 MySQL 字符集。如果 Client 端不支持匹配的字符集,则使用默认编译器。
- 每个 Client 端都支持“--default-character-set”选项,该选项使用户可以显式指定字符集,以覆盖 Client 端否则确定的默认值。
- 使用 mysqlClient 端,要使用与默认字符集不同的字符集:
- 可以在每次连接到服务器时显式执行“SET NAMES”语句。
- 也可以请在选项文件中指定字符集。例如:
[mysql] default-character-set=koi8r
- 使用 mysqlClient 端,要使用与默认字符集不同的字符集:
- 如果使用的是启用了自动重新连接的 mysqlClient 端(不建议这样做),则最好使用“charset”命令而不是“SET NAMES”。例如:【???】
mysql> charset koi8r Charset changed
- “charset”命令发出“SET NAMES”语句,并更改 mysql 在断开连接后重新连接时使用的默认字符集。
用于连接字符集配置的 SQL 语句
构建连接后,Client 端可以更改当前会话的字符集和整理系统变量。可以使用“SET”语句分别更改这些变量,但是还有两个更方便的语句会成组地影响与连接相关的字符集系统变量:
SET NAMES 'charset_name' [COLLATE 'collation_name']
- “SET NAMES”指示 Client 端将使用什么字符集将 SQL 语句发送到服务器,它还指定服务器用于将结果发送回 Client 端的字符集。
“SET NAMES 'charset_name'”语句等效于以下三个语句:
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_name;
“SET CHARACTER SET 'charset_name '”语句与“SET NAMES”类似,但是将“character_set_connection”和“collation_connection”设置为“character_set_database”和“collation_database”(默认数据库的字符集和排序规则)。
- 将“character_set_connection”设置为“charset_name”也会将“collation_connection”隐式设置为“charset_name”的默认排序规则。不必显式设置该排序规则。要指定用于“collation_connection”的特定排序规则,请添加“COLLATE”子句:
SET NAMES 'charset_name' COLLATE 'collation_name'
- 设置“collation_connection”还会将“character_set_connection”隐式设置为与排序规则关联的字符集(等同于执行“SET character_set_connection = @@character_set_database”)。不必显式设置“character_set_connection”。
连接字符集错误处理
尝试使用不合适的连接字符集或排序规则会产生错误,或导致服务器退回到给定连接的默认字符集和排序规则。
连接时错误处理
- 如果您指定了有效但不能作为 Client 端字符集的字符集,则服务器将返回错误:
shell> mysql --default-character-set=ucs2 ERROR 1231 (42000): Variable 'character_set_client' can't be set to the value of 'ucs2'
- 如果指定了 Client 端无法识别的字符集,则会产生错误:
shell> mysql --default-character-set=bogus mysql: Character set 'bogus' is not a compiled character set and is not specified in the '/usr/local/mysql/share/charsets/Index.xml' file ERROR 2019 (HY000): Can't initialize character set bogus (path: /usr/local/mysql/share/charsets/)
- 如果指定了 Client 端可以识别但服务器不能识别的字符集,则服务器将退回到其默认字符集和排序规则:
- 假设服务器配置为使用latin1和latin1_swedish_ci作为其默认值,并且不能将gb18030识别为有效字符集。指定--default-character-set=gb18030的 Client 端可以连接到服务器,但是生成的字符集不是 Client 端想要的:
mysql> SHOW SESSION VARIABLES LIKE 'character\_set\_%'; +--------------------------+--------+ | Variable_name | Value | +--------------------------+--------+ | character_set_client | latin1 | | character_set_connection | latin1 | ... | character_set_results | latin1 | ... +--------------------------+--------+ mysql> SHOW SESSION VARIABLES LIKE 'collation_connection'; +----------------------+-------------------+ | Variable_name | Value | +----------------------+-------------------+ | collation_connection | latin1_swedish_ci | +----------------------+-------------------+
- 如上,服务器无法满足 Client 端字符集请求,并退回到其默认值(服务器无法满足 Client 端字符集请求,并退回到其默认值)。
- 当 Client 端告诉服务器使用服务器可以识别的字符集,但是服务器端不知道 Client 端上该字符集的默认排序规则:
- 例如,当 MySQL 8.0Client 端希望使用 utf8mb4 作为 Client 端字符集连接到 MySQL 5.7 服务器时,就会发生这种情况。指定“--default-character-set=utf8mb4”的 Client 端可以连接到服务器。
mysql> SHOW SESSION VARIABLES LIKE 'character\_set\_%'; +--------------------------+--------+ | Variable_name | Value | +--------------------------+--------+ | character_set_client | latin1 | | character_set_connection | latin1 | ... | character_set_results | latin1 | ... +--------------------------+--------+ mysql> SHOW SESSION VARIABLES LIKE 'collation_connection'; +----------------------+-------------------+ | Variable_name | Value | +----------------------+-------------------+ | collation_connection | latin1_swedish_ci | +----------------------+-------------------+
- 如上,服务器回退到其默认字符集和排序规则,而不是 Client 端请求的内容。其原因:
- utf8mb4 的默认排序规则在 MySQL 5.7 和 8.0 之间有所不同(“utf8mb4_general_ci”表示 5.7,“utf8mb4_0900_ai_ci”表示 8.0)。
- 当 8.0 Client 端请求字符集 utf8mb4 时,它发送给服务器的是默认的 8.0 utf8mb4 排序规则;即 utf8mb4_0900_ai_ci。
- utf8mb4_0900_ai_ci 仅从 MySQL 8.0 开始实现,因此 5.7 服务器无法识别它。
- 因为 5.7 服务器无法识别 utf8mb4_0900_ai_ci,所以它不能满足 Client 端字符集请求,并退回到其默认字符集和排序规则(latin1 和 latin1_swedish_ci)。
- 在这种情况下,Client 端在连接后仍然可以通过发出“SET NAMES 'utf8mb4'”语句来使用 utf8mb4。生成的整理是 5.7 默认 utf8mb4 排序规则;就是 utf8mb4_general_ci。
运行时错误处理
在已构建的连接,Client 端可以请求更改连接字符集并使用“SET NAMES”或“SET CHARACTER SET”进行排序规则。
- 如果您指定了有效但不能作为 Client 端字符集的字符集,则服务器将返回错误:
mysql> SET NAMES 'ucs2'; ERROR 1231 (42000): Variable 'character_set_client' can't be set to the value of 'ucs2'
- 如果服务器无法识别字符集(或排序规则),则会产生错误:
mysql> SET NAMES 'bogus'; ERROR 1115 (42000): Unknown character set: 'bogus' mysql> SET NAMES 'utf8mb4' COLLATE 'bogus'; ERROR 1273 (HY000): Unknown collation: 'bogus'
- 想要验证服务器是否遵循其请求的字符集的 Client 端,可以在连接并检查结果是否为预期的字符集后执行以下语句:
SELECT @@character_set_client;