一个 “连接” 是客户端程序在连接到服务器时建立的,用于开始一个会话,在此会话中,客户端程序可以与服务器进行交互。客户端通过会话连接发送 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
字符集。” 它还指定了服务器应该用于将结果发送回客户端的字符集。(例如,如果使用生成结果集的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
,服务器会使用客户端在连接时指定的字符集发送回 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;