12.4 连接字符集和排序规则
客户端程序在连接到服务器时,创建一个“连接”,以开始一个会话,在这个会话中它与服务器交互。客户端将SQL语句,如查询,通过会话连接发送给服务器。服务器将结果集或错误信息,通过连接回传给客户端。
一些字符集和排序规则系统变量与客户端的交互相关,这些变量在前面部分已经提到过:
-
服务器系统变量
character_set_server
和collation_server
指示服务器字符集和排序规则。见第12.3.2节,“服务器字符集和排序规则”。 -
服务器系统变量
character_set_database
和collation_database
指示默认数据库的字符集和排序规则。见第12.3.3节,“数据库字符集和排序规则”。
在客户端和服务器之间的连接中,还有其他字符集和排序规则系统变量参与处理。每个客户端都有会话特定的连接相关字符集和排序规则系统变量。这些会话系统变量值是在连接时初始化的,但可以在会话中更改。
关于客户端连接中的字符集和排序规则处理,可以通过系统变量来回答问题:
-
离开客户端时,语句使用什么字符集?
服务器将
character_set_client
系统变量作为客户端发送语句的字符集。Note某些字符集不能用作客户端字符集。见不允许的客户端字符集。
-
服务器收到语句后,应该将它们翻译成什么字符集?
服务器使用
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
设置为指定的字符集:
-
系统变量
--default-character-set=
由 MySQL 客户端程序,如mysql和mysqladmin使用。charset_name
客户端程序连接字符集配置
当客户端连接到服务器时,它将指示要使用的字符集来与服务器进行通信。实际上,客户端指示该字符集的默认排序规则,从而使服务器可以确定字符集。服务器使用这个信息将character_set_client
、character_set_results
、character_set_connection
系统变量设置为字符集,并将collation_connection
设置为字符集默认排序规则。实际上,服务器执行了等同于SET NAMES
操作。
如果服务器不支持请求的字符集或排序规则,它将使用服务器字符集和排序规则来配置连接。关于这个 fallback 行为的详细信息,请参见连接字符集错误处理。
mysql、mysqladmin、mysqlcheck、mysqlimport 和 mysqlshow 客户端程序确定使用的默认字符集如下:
-
在缺少其他信息的情况下,每个客户端都使用编译时的默认字符集,通常是
utf8mb4
。 -
每个客户端可以根据操作系统设置自动检测字符集,例如 Unix 系统中的
LANG
或LC_ALL
环境变量值,或者 Windows 系统中的代码页设置。对于支持 locale 的系统,客户端使用它来设置默认字符集,而不是使用编译时的默认字符集。例如,将LANG
设置为ru_RU.KOI8-R
则使用koi8r
字符集。因此,用户可以在环境中配置 locale,以便 MySQL 客户端使用。如果 OS 字符集没有精确匹配的映射,客户端将使用编译时的默认字符集。如果客户端不支持匹配字符集,它将使用编译时的默认字符集。例如,
utf8
和utf-8
映射到utf8mb4
,而ucs2
不支持连接字符集,所以它映射到编译时的默认字符集。C 应用程序可以使用 OS 设置来自动检测字符集,通过在连接服务器前调用
mysql_options()
如下方式:mysql_options(mysql, MYSQL_SET_CHARSET_NAME, MYSQL_AUTODETECT_CHARSET_NAME);
-
每个客户端都支持一个
--default-character-set
选项,允许用户指定字符集,以便覆盖客户端其他方式确定的默认字符集。Note某些字符集不能用作客户端字符集。使用
--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
中。” 它还指定服务器应该使用什么字符集将结果发送回客户端。例如,如果您使用SELECT
语句生成结果集,它就指示该字符集用于列值。一个
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
,服务器将使用客户端连接时指定的字符集发送所有值。反之,如果您在发出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;