一个 “连接” 是客户端程序连接到服务器时所建立的,用于在会话中与服务器交互的会话连接。客户端通过会话连接发送 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
。例外:对于带有introducer的字符串文字,例如_utf8mb4
或_latin2
,introducer确定字符集。请参阅第 12.3.8 节,“字符集 Introducers”。 -
collation_connection
对于字符串文字的比较非常重要。对于字符串与列值的比较,collation_connection
不重要,因为列有其自己的排序,具有更高的排序优先级(请参阅第 12.8.4 节,“表达式中的排序 Coercibility”)。
-
-
服务器应该将查询结果翻译成什么字符集,然后将其返回给客户端?
服务器使用
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
locale 环境变量的值,或者 Windows 系统上的代码页设置。对于可以从 OS 获取 locale 的系统,客户端使用它来设置默认字符集,而不是使用编译的默认值。例如,将LANG
设置为ru_RU.KOI8-R
将导致使用koi8r
字符集。因此,用户可以在环境中配置 locale,以便 MySQL 客户端使用。操作系统字符集将映射到 MySQL 字符集的最近匹配项,如果没有精确匹配。如果客户端不支持匹配的字符集,它将使用编译的默认值。例如,
utf8
和utf-8
映射到utf8mb4
,而ucs2
不支持作为连接字符集,因此映射到编译的默认值。C 应用程序可以通过在连接到服务器之前调用
mysql_options()
来基于操作系统设置进行字符集自动检测:mysql_options(mysql, MYSQL_SET_CHARSET_NAME, MYSQL_AUTODETECT_CHARSET_NAME);
-
每个客户端都支持一个
--default-character-set
选项,允许用户明确指定字符集以覆盖客户端otherwise 确定的默认值。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 字符集
与SET NAMES
相似,但设置character_set_connection
和collation_connection
为character_set_database
和collation_database
(如前所述,表示默认数据库的字符集和排序规则)。一个
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 字符集
将产生错误。请参阅 不可用的客户端字符集。
示例:假设 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
。这是因为服务器无法满足客户端字符集请求,fallback 到其默认值。
在这种情况下,客户端无法使用它想要的字符集,因为服务器不支持它。客户端必须愿意使用不同的字符集,或者连接到支持所需字符集的不同服务器。
同样的问题也发生在客户端告诉服务器使用服务器识别的字符集,但客户端侧的默认排序规则在服务器侧未知的情况下。
运行时错误处理
在已建立的连接中,客户端可以使用 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'
想要验证其请求的字符集是否被服务器honored 的客户端可以在连接后执行以下语句,并检查结果是否是预期的字符集:
SELECT @@character_set_client;