一个 “连接” 是客户端程序连接到服务器时建立的,它会开启一个会话,让客户端在会话中与服务器交互。客户端通过会话连接发送 SQL 语句,例如查询。服务器通过连接将响应(例如结果集或错误消息)发回给客户端。
几个字符集和排序规则系统变量与客户端与服务器的交互相关。在前面的章节中已经提到过其中一些变量。
character_set_server
和collation_server
系统变量指示服务器字符集和排序规则。请参见 第 12.3.2 节,“服务器字符集和排序规则”。character_set_database
和collation_database
系统变量指示默认数据库的字符集和排序规则。请参见 第 12.3.3 节,“数据库字符集和排序规则”。
其他字符集和排序规则系统变量参与处理客户端与服务器之间的连接流量。每个客户端都有特定于会话的连接相关字符集和排序规则系统变量。这些会话系统变量值在连接时初始化,但可以在会话中更改。
有关客户端连接的字符集和排序规则处理的几个问题,可以用系统变量来回答。
语句离开客户端时使用什么字符集?
服务器将
character_set_client
系统变量视为客户端发送语句所使用的字符集。注意某些字符集不能用作客户端字符集。请参见 不允许的客户端字符集。
服务器在接收语句后应该将语句翻译成什么字符集?
为了确定这一点,服务器会使用
character_set_connection
和collation_connection
系统变量。服务器会将客户端发送的语句从
character_set_client
转换为character_set_connection
。例外情况:对于具有引入器(例如_utf8mb4
或_latin2
)的字符串文字,引入器会确定字符集。请参见 第 12.3.8 节,“字符集引入器”。collation_connection
对文字字符串的比较很重要。对于字符串与列值的比较,collation_connection
并不重要,因为列有自己的排序规则,该排序规则具有更高的排序规则优先级(请参见 第 12.8.4 节,“表达式中的排序规则强制性”)。
服务器在将查询结果发回客户端之前应该将查询结果翻译成什么字符集?
character_set_results
系统变量指示服务器将查询结果以何种字符集返回给客户端。这包括结果数据(例如列值)、结果元数据(例如列名)和错误消息。要告诉服务器不执行结果集或错误消息的转换,请将
character_set_results
设置为NULL
或binary
。SET character_set_results = NULL; SET character_set_results = binary;
有关字符集和错误消息的更多信息,请参见 第 12.6 节,“错误消息字符集”。
要查看应用于当前会话的字符集和排序规则系统变量的值,请使用以下语句:
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;
以下更简单的语句也会显示连接变量,但也会包含其他相关变量。它们对于查看 所有 字符集和排序规则系统变量很有用:
SHOW SESSION VARIABLES LIKE 'character\_set\_%';
SHOW SESSION VARIABLES LIKE 'collation\_%';
客户端可以微调这些变量的设置,也可以依赖默认设置(在这种情况下,您可以跳过本节的其余部分)。如果您不使用默认设置,则必须 针对与服务器的每次连接 更改字符设置。
character_set_client
系统变量不能设置为某些字符集。
ucs2
utf16
utf16le
utf32
尝试将这些字符集中的任何一个用作客户端字符集会产生错误。
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
设置为指定的字符集。
MySQL 客户端程序(例如 mysql 和 mysqladmin)使用的
--default-character-set=
命令选项。charset_name
当客户端连接到服务器时,它会指示它想要使用哪个字符集与服务器进行通信。(实际上,客户端指示该字符集的默认排序规则,服务器可以从中确定字符集。)服务器使用此信息来设置 character_set_client
、character_set_results
、character_set_connection
系统变量为字符集,以及 collation_connection
为字符集默认排序规则。实际上,服务器执行相当于 SET NAMES
操作。
如果服务器不支持请求的字符集或排序规则,它将回退到使用服务器字符集和排序规则来配置连接。有关此回退行为的更多详细信息,请参阅 连接字符集错误处理。
mysql、mysqladmin、mysqlcheck、mysqlimport 和 mysqlshow 客户端程序确定要使用的默认字符集,如下所示
在没有其他信息的情况下,每个客户端都使用编译后的默认字符集,通常是
utf8mb4
。每个客户端都可以根据操作系统设置自动检测要使用的字符集,例如 Unix 系统上
LANG
或LC_ALL
本地环境变量的值,或 Windows 系统上的代码页设置。对于操作系统上提供本地设置的系统,客户端使用它来设置默认字符集,而不是使用编译后的默认字符集。例如,将LANG
设置为ru_RU.KOI8-R
会导致使用koi8r
字符集。因此,用户可以在其环境中配置本地设置,以便 MySQL 客户端使用。如果操作系统字符集没有完全匹配,则映射到最接近的 MySQL 字符集。如果客户端不支持匹配的字符集,则它使用编译后的默认字符集。例如,
utf8
和utf-8
映射到utf8mb4
,而ucs2
不支持作为连接字符集,因此它映射到编译后的默认字符集。C 应用程序可以通过调用
mysql_options()
来使用基于操作系统设置的字符集自动检测,如下所示,在连接到服务器之前mysql_options(mysql, MYSQL_SET_CHARSET_NAME, MYSQL_AUTODETECT_CHARSET_NAME);
每个客户端都支持一个
--default-character-set
选项,它允许用户显式指定字符集,以覆盖客户端否则确定的任何默认值。注意某些字符集不能用作客户端字符集。尝试使用
--default-character-set
使用它们会导致错误。请参阅 不允许的客户端字符集。
使用 mysql 客户端,要使用与默认字符集不同的字符集,可以每次连接到服务器时显式执行 SET NAMES
语句(请参阅 客户端程序连接字符集配置)。为了更轻松地实现相同的结果,可以在选项文件中指定字符集。例如,以下选项文件设置会在每次调用 mysql 时将三个与连接相关的字符集系统变量设置为 koi8r
[mysql]
default-character-set=koi8r
如果使用启用了自动重新连接的 mysql 客户端(不推荐),最好使用 charset
命令,而不是 SET NAMES
。例如
mysql> charset koi8r
Charset changed
charset
命令会发出 SET NAMES
语句,还会更改 mysql 在连接断开后重新连接时使用的默认字符集。
在配置客户端程序时,还必须考虑其执行的环境。请参阅 第 12.5 节“配置应用程序字符集和排序规则”。
建立连接后,客户端可以更改当前会话的字符集和排序规则系统变量。可以使用 SET
语句单独更改这些变量,但还有两个更方便的语句可以将与连接相关的字符集系统变量作为一组进行更改
SET NAMES '
charset_name
' [COLLATE 'collation_name
']SET NAMES
指示客户端使用什么字符集将 SQL 语句发送到服务器。因此,SET NAMES 'cp1251'
会告诉服务器,““来自此客户端的未来传入消息使用字符集cp1251
。”一个
SET NAMES '
语句等效于以下三个语句charset_name
'SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name;
将
character_set_connection
设置为charset_name
还会隐式地将collation_connection
设置为charset_name
的默认排序规则。无需显式设置该排序规则。要指定要用于collation_connection
的特定排序规则,请添加一个COLLATE
子句SET NAMES 'charset_name' COLLATE 'collation_name'
SET CHARACTER SET '
'charset_name
SET CHARACTER SET
与SET NAMES
类似,但会将character_set_connection
和collation_connection
设置为character_set_database
和collation_database
(如前所述,它们指示默认数据库的字符集和排序规则)。一个
SET CHARACTER SET
语句等效于以下三个语句charset_name
SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database;
设置
collation_connection
还会隐式地将character_set_connection
设置为与排序规则关联的字符集(等效于执行SET character_set_connection = @@character_set_database
)。无需显式设置character_set_connection
。
某些字符集不能用作客户端字符集。尝试使用 SET NAMES
或 SET CHARACTER SET
使用它们会导致错误。请参阅 不允许的客户端字符集。
例如:假设 column1
定义为 CHAR(5) CHARACTER SET latin2
。如果不使用 SET NAMES
或 SET CHARACTER SET
,则对于 SELECT column1 FROM t
,服务器会使用客户端连接时指定的字符集发送回 column1
的所有值。另一方面,如果在发出 SELECT
语句之前使用 SET NAMES 'latin1'
或 SET CHARACTER SET 'latin1'
,服务器会在将结果发送回之前将 latin2
值转换为 latin1
。对于不在两个字符集中都存在的字符,转换可能会导致丢失。
尝试使用不合适的连接字符集或排序规则可能会产生错误,或导致服务器回退到给定连接的默认字符集和排序规则。本节描述在配置连接字符集时可能出现的错误。这些错误可能在建立连接时或在更改已建立连接中的字符集时出现。
连接时错误处理
某些字符集不能用作客户端字符集;请参阅 不允许的客户端字符集。如果指定有效的字符集,但不能用作客户端字符集,服务器将返回错误
$> mysql --default-character-set=ucs2
ERROR 1231 (42000): Variable 'character_set_client' can't be set to
the value of 'ucs2'
如果指定客户端无法识别的字符集,它将产生错误
$> 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/)
如果指定客户端可以识别但服务器无法识别的字符集,服务器将回退到其默认字符集和排序规则。假设服务器配置为使用 latin1
和 latin1_swedish_ci
作为其默认值,并且它无法识别 gb18030
作为有效字符集。指定 --default-character-set=gb18030
的客户端能够连接到服务器,但结果字符集不是客户端想要的
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 |
+----------------------+-------------------+
可以发现,连接系统变量已被设置为反映 latin1
和 latin1_swedish_ci
的字符集和排序规则。这是因为服务器无法满足客户端字符集请求,因此回退到其默认值。
在这种情况下,客户端无法使用它想要的字符集,因为服务器不支持它。客户端必须愿意使用其他字符集,或者连接到支持所需字符集的其他服务器。
当客户端告诉服务器使用服务器可以识别但客户端默认排序规则在服务器端未知的字符集时,也会出现同样的问题。
运行时错误处理
在已建立的连接中,客户端可以使用SET NAMES
或 SET CHARACTER SET
请求更改连接字符集和排序规则。
某些字符集不能用作客户端字符集;请参阅 不允许的客户端字符集。如果指定有效的字符集,但不能用作客户端字符集,服务器将返回错误
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'
想要验证服务器是否已认可其请求的字符集的客户端可以在连接后执行以下语句,并检查结果是否为预期字符集。
SELECT @@character_set_client;