## 10.4 连接字符集和排序规则

[](<>)[](<>)

“连接”是客户端程序在连接到服务器时所做的，以开始与服务器交互的会话。客户端通过会话连接发送 SQL 语句，例如查询。服务器通过连接将响应（例如结果集或错误消息）发送回客户端。

-   [连接字符集和排序规则系统变量](charset-connection.html#charset-connection-system-variables)

-   [不允许的客户端字符集](charset-connection.html#charset-connection-impermissible-client-charset)

-   [客户端程序连接字符集配置](charset-connection.html#charset-connection-client-configuration)

-   [连接字符集配置的 SQL 语句](charset-connection.html#charset-connection-sql-statements)

-   [连接字符集错误处理](charset-connection.html#charset-connection-error-handling)

### 连接字符集和排序规则系统变量

几个字符集和排序规则系统变量与客户端与服务器的交互有关。其中一些已经在前面的章节中提到过：

-   这[`character_set_server`](server-system-variables.html#sysvar_character_set_server)和[`collat​​ion_server`](server-system-variables.html#sysvar_collation_server)系统变量指示服务器字符集和排序规则。看[第 10.3.2 节，“服务器字符集和排序规则”](charset-server.html).

-   这[`字符集数据库`](server-system-variables.html#sysvar_character_set_database)和[`collat​​ion_database`](server-system-variables.html#sysvar_collation_database)系统变量表示默认数据库的字符集和排序规则。看[第 10.3.3 节，“数据库字符集和排序规则”](charset-database.html).

    额外的字符集和排序规则系统变量涉及处理客户端和服务器之间的连接的流量。每个客户端都有特定于会话的连接相关字符集和排序规则系统变量。这些会话系统变量值在连接时初始化，但可以在会话内更改。

    关于客户端连接的字符集和排序规则处理的几个问题可以根据系统变量来回答：

-   离开客户端时的语句是什么字符集？

    服务器采取[`character_set_client`](server-system-variables.html#sysvar_character_set_client)系统变量是客户端发送语句的字符集。

    笔记

    某些字符集不能用作客户端字符集。看[不允许的客户端字符集](charset-connection.html#charset-connection-impermissible-client-charset).

-   服务器收到语句后应该将它们翻译成什么字符集？

    为了确定这一点，服务器使用[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)和[`collat​​ion_connection`](server-system-variables.html#sysvar_collation_connection)系统变量：

    -   服务器将客户端发送的语句从[`character_set_client`](server-system-variables.html#sysvar_character_set_client)到[`字符集连接`](server-system-variables.html#sysvar_character_set_connection).例外：对于具有引入者的字符串文字，例如`_utf8mb4`要么`_latin2`，介绍人确定字符集。看[第 10.3.8 节，“字符集介绍器”](charset-introducer.html).

    -   [`collat​​ion_connection`](server-system-variables.html#sysvar_collation_connection)对于比较文字字符串很重要。对于字符串与列值的比较，[`collat​​ion_connection`](server-system-variables.html#sysvar_collation_connection)没关系，因为列有自己的排序规则，它具有更高的排序规则优先级（参见[第 10.8.4 节，“表达式中的排序规则强制性”](charset-collation-coercibility.html)）。

-   在将查询结果发送回客户端之前，服务器应将查询结果转换为什么字符集？

    这[`字符集结果`](server-system-variables.html#sysvar_character_set_results)系统变量表示服务器向客户端返回查询结果的字符集。这包括结果数据（如列值）、结果元数据（如列名）和错误消息。

    要告诉服务器不执行结果集或错误消息的转换，请设置[`字符集结果`](server-system-variables.html#sysvar_character_set_results)到`空值`要么`二进制`：

    ```
    SET character_set_results = NULL;
    SET character_set_results = binary;
    ```

    有关字符集和错误消息的更多信息，请参阅[第 10.6 节，“错误消息字符集”](charset-errors.html).

    要查看适用于当前会话的字符集和排序规则系统变量的值，请使用以下语句：


```
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`](server-system-variables.html#sysvar_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`](server-system-variables.html#sysvar_character_set_client)到命名字符集：

-   这[`--默认字符集=*`字符集名称`*`](mysql-command-options.html#option_mysql_default-character-set)MySQL 客户端程序使用的命令选项，例如[**mysql**](mysql.html)和[**mysql管理员**](mysqladmin.html).

-   这[`设置名称'*`字符集名称`*'`](set-names.html)陈述。

-   这[`设置字符集'*`字符集名称`*'`](set-character-set.html)陈述。

### 客户端程序连接字符集配置

当客户端连接到服务器时，它会指示它想要使用哪个字符集与服务器通信。（实际上，客户端指示该字符集的默认排序规则，服务器可以从中确定字符集。）服务器使用此信息来设置[`character_set_client`](server-system-variables.html#sysvar_character_set_client),[`字符集结果`](server-system-variables.html#sysvar_character_set_results),[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)字符集的系统变量，以及[`collat​​ion_connection`](server-system-variables.html#sysvar_collation_connection)到字符集默认排序规则。实际上，服务器执行相当于[`设置名称`](set-names.html)手术。

如果服务器不支持请求的字符集或排序规则，它会回退到使用服务器字符集和排序规则来配置连接。有关此回退行为的更多详细信息，请参阅[连接字符集错误处理](charset-connection.html#charset-connection-error-handling).

这[**mysql**](mysql.html),[**mysql管理员**](mysqladmin.html),[**mysql检查**](mysqlcheck.html),[**mysql导入**](mysqlimport.html)， 和[**mysqlshow**](mysqlshow.html)客户端程序确定要使用的默认字符集如下：

-   在没有其他信息的情况下，每个客户端都使用编译进来的默认字符集，通常`utf8mb4`.

-   每个客户端都可以根据操作系统设置自动检测要使用的字符集，例如`朗`要么`LC_ALL`Unix 系统上的语言环境变量或 Windows 系统上的代码页设置。对于可以从 OS 获得区域设置的系统，客户端使用它来设置默认字符集，而不是使用编译后的默认值。例如，设置`朗`到`ru_RU.KOI8-R`导致`锦鲤8r`要使用的字符集。因此，用户可以在他们的环境中配置区域设置以供 MySQL 客户端使用。

    如果没有完全匹配，则 OS 字符集映射到最接近的 MySQL 字符集。如果客户端不支持匹配的字符集，它使用编译的默认值。例如，`utf8`和`utf-8`映射到`utf8mb4`， 和`ucs2`不支持作为连接字符集，因此它映射到编译的默认值。

    C 应用程序可以通过调用来使用基于操作系统设置的字符集自动检测[`mysql_options()`](https://dev.mysql.com/doc/c-api/8.0/en/mysql-options.html)连接服务器前如下：

    ```
    mysql_options(mysql,
                  MYSQL_SET_CHARSET_NAME,
                  MYSQL_AUTODETECT_CHARSET_NAME);
    ```

-   每个客户端支持一个[`--默认字符集`](mysql-command-options.html#option_mysql_default-character-set)选项，它使用户能够显式指定字符集以覆盖客户端以其他方式确定的任何默认值。

    笔记

    某些字符集不能用作客户端字符集。尝试将它们与[`--默认字符集`](mysql-command-options.html#option_mysql_default-character-set)产生错误。看[不允许的客户端字符集](charset-connection.html#charset-connection-impermissible-client-charset).

    随着[**mysql**](mysql.html)客户端，要使用与默认字符集不同的字符集，您可以显式执行[`设置名称`](set-names.html)每次连接到服务器时的语句（请参阅[客户端程序连接字符集配置](charset-connection.html#charset-connection-client-configuration)）。要更轻松地完成相同的结果，请在选项文件中指定字符集。例如，以下选项文件设置将三个与连接相关的字符集系统变量设置为`锦鲤8r`每次调用[**mysql**](mysql.html)：


```
[mysql]
default-character-set=koi8r
```

如果您正在使用[**mysql**](mysql.html)启用自动重新连接的客户端（不推荐），最好使用`字符集`命令而不是[`设置名称`](set-names.html).例如：

```
mysql> charset koi8r
Charset changed
```

这`字符集`命令发出一个[`设置名称`](set-names.html)语句，并且还更改了默认字符集[**mysql**](mysql.html)在连接断开后重新连接时使用。

在配置客户端程序时，您还必须考虑它们执行的环境。看[第 10.5 节，“配置应用程序字符集和排序规则”](charset-applications.html).

### 连接字符集配置的 SQL 语句

建立连接后，客户端可以更改当前会话的字符集和排序规则系统变量。这些变量可以单独使用[`放`](set-statement.html)语句，但有两个更方便的语句将连接相关的字符集系统变量作为一个组来影响：

-   `设置名称'*`字符集名称`*' [整理'*`collat​​ion_name`*']`

    [`设置名称`](set-names.html)指示客户端用于向服务器发送 SQL 语句的字符集。因此，[`设置名称“cp1251”`](set-names.html)告诉服务器，“将来从这个客户端传入的消息都是字符集`cp1251`“它还指定了服务器应用于将结果发送回客户端的字符集。（例如，如果使用[`选择`](select.html)生成结果集的语句。）

    A.[`定名*`charset\_名称`*'`](set-names.html)语句相当于这三种语句：

    ```
    SET character_set_client = charset_name;
    SET character_set_results = charset_name;
    SET character_set_connection = charset_name;
    ```

    背景[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)到*`charset_名称`*还隐式设置[`校对连接`](server-system-variables.html#sysvar_collation_connection)到的默认排序规则*`charset_名称`*。没有必要显式设置该排序规则。指定要用于的特定排序规则[`校对连接`](server-system-variables.html#sysvar_collation_connection)，添加一个`整理`条款：

    ```
    SET NAMES 'charset_name' COLLATE 'collation_name'
    ```

-   `设置字符集'*`charset\_名称`*`'

    [`集合字符集`](set-character-set.html)类似于[`定名`](set-names.html)但是设置[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)和[`校对连接`](server-system-variables.html#sysvar_collation_connection)到[`字符集数据库`](server-system-variables.html#sysvar_character_set_database)和[`整理数据库`](server-system-variables.html#sysvar_collation_database)（如前所述，它指示默认数据库的字符集和排序规则）。

    A.[`集合字符集*`charset\_名称`*`](set-character-set.html)语句相当于这三种语句：

    ```
    SET character_set_client = charset_name;
    SET character_set_results = charset_name;
    SET collation_connection = @@collation_database;
    ```

    背景[`校对连接`](server-system-variables.html#sysvar_collation_connection)还隐式设置[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)与排序规则关联的字符集（相当于执行`设置字符集连接=@@character\u SET\u数据库`).没有必要设置[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)明确地

笔记

某些字符集不能用作客户端字符集。试图将它们用于[`定名`](set-names.html)或[`集合字符集`](set-character-set.html)产生一个错误。看见[不允许的客户端字符集](charset-connection.html#charset-connection-impermissible-client-charset).

假设`专栏1`定义为`字符（5）字符集2`.如果你不说[`定名`](set-names.html)或[`集合字符集`](set-character-set.html)，那么`从t中选择column1`，服务器会发回`专栏1`使用客户端连接时指定的字符集。另一方面，如果你说`设置名称“latin1”`或`设置字符集“latin1”`在发布[`选择`](select.html)语句，服务器将`拉丁语2`价值观`拉丁语1`就在返回结果之前。对于不在两个字符集中的字符，转换可能会有损。

### 连接字符集错误处理

尝试使用不适当的连接字符集或排序规则可能会产生错误，或导致服务器退回到给定连接的默认字符集和排序规则。本节介绍配置连接字符集时可能出现的问题。在建立连接或更改已建立连接中的字符集时，可能会出现这些问题。

-   [连接时间错误处理](charset-connection.html#charset-connection-error-handling-connect-time)

-   [运行时错误处理](charset-connection.html#charset-connection-error-handling-runtime)

#### 连接时间错误处理

某些字符集不能用作客户端字符集；看见[不允许的客户端字符集](charset-connection.html#charset-connection-impermissible-client-charset)。如果指定了有效但不允许作为客户端字符集的字符集，服务器将返回错误：

```
$> 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/)
```

如果指定了一个客户机可以识别但服务器不能识别的字符集，则服务器会返回其默认字符集和排序规则。假设服务器配置为使用`拉丁语1`和`拉丁语瑞典语`作为它的默认值，它不承认`gb18030`作为有效的字符集。指定[`--默认字符集=gb18030`](mysql-command-options.html#option_mysql_default-character-set)能够连接到服务器，但生成的字符集不是客户端想要的：

```
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 |
+----------------------+-------------------+
```

您可以看到，已将连接系统变量设置为反映`拉丁语1`和`拉丁语瑞典语`。发生这种情况的原因是服务器无法满足客户端字符集请求，并返回其默认值。

在这种情况下，客户端无法使用它想要的字符集，因为服务器不支持它。客户端必须愿意使用不同的字符集，或者连接到支持所需字符集的不同服务器。

同样的问题也发生在更微妙的上下文中：当客户端告诉服务器使用服务器可以识别的字符集，但服务器端不知道该字符集在客户端的默认排序规则时。例如，当MySQL 8.0客户端希望使用`utf8mb4`作为客户端字符集。指定[`--默认字符集=utf8mb4`](mysql-command-options.html#option_mysql_default-character-set)能够连接到服务器。但是，与前一个示例一样，服务器返回到其默认字符集和排序规则，而不是客户端所请求的：

```
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 |
+----------------------+-------------------+
```

为什么会发生这种情况？毕竟`utf8mb4`8.0客户端和5.7服务器都知道它，所以它们都能识别它。为了理解这种行为，有必要理解，当客户机告诉服务器它想要使用哪个字符集时，它实际上会告诉服务器该字符集的默认排序规则。因此，上述行为的发生是多种因素共同作用的结果：

-   的默认排序规则`utf8mb4`MySQL 5.7和8.0之间的差异(`utf8mb4_通用_ci`对于5.7，`utf8mb4_0900_ai_ci`8.0版）。

-   当8.0客户端请求`utf8mb4`，它发送到服务器的是默认的8.0`utf8mb4`校勘；就是`utf8mb4_0900_ai_ci`.

-   `utf8mb4_0900_ai_ci`仅在MySQL 8.0中实现，因此5.7服务器无法识别它。

-   因为5.7服务器无法识别`utf8mb4_0900_ai_ci`，它无法满足客户端字符集请求，并返回到其默认字符集和排序规则(`拉丁语1`和`拉丁语瑞典语`).

    在这种情况下，客户端仍然可以使用`utf8mb4`通过发布`设置名称“utf8mb4”`连接后的声明。由此产生的排序规则是5.7默认值`utf8mb4`校勘；就是，`utf8mb4_通用_ci`.如果客户另外需要`utf8mb4_0900_ai_ci`，它无法实现这一点，因为服务器无法识别该排序规则。客户必须愿意使用不同的`utf8mb4`排序规则，或从MySQL 8.0或更高版本连接到服务器。

#### 运行时错误处理

在已建立的连接中，客户端可以请求更改连接字符集和排序规则[`定名`](set-names.html)或[`集合字符集`](set-character-set.html).

某些字符集不能用作客户端字符集；看见[不允许的客户端字符集](charset-connection.html#charset-connection-impermissible-client-charset)。如果指定了有效但不允许作为客户端字符集的字符集，服务器将返回错误：

```
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;
```
