# 15.1 字符集

在本教程中，您将了解MySQL中的字符集。 在本教程之后，您将了解如何获取MySQL中的所有字符集，如何在字符集之间转换字符串以及如何为客户端连接配置正确的字符集。

## MySQL字符集简介

MySQL字符集是一组在字符串中合法的字符。 例如，我们有一个从`a`到`z`的字母。要为每个字母分配一个数字，例如`a = 1`，`b = 2`等。字母`a`是一个符号，数字`1`与字母`a`相关联就是一种编码。 从`a`到`z`的所有字母和它们相应的编码的组合是一个字符集。

每个字符集具有一个或多个排序规则，其定义用于比较字符集中的字符的一组规则。 查看[MySQL排序规则教程](http://www.yiibai.com/mysql/collation.html)，了解MySQL排序规则。

MySQL支持各种字符集，允许您几乎可将每个字符存储在字符串中。 要获取MySQL数据库服务器中的所有可用字符集，请使用`SHOW CHARACTER SET`语句如下：

```sql
mysql> SHOW CHARACTER SET;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
| dec8     | DEC West European               | dec8_swedish_ci     |      1 |
| cp850    | DOS West European               | cp850_general_ci    |      1 |
| hp8      | HP West European                | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian           | koi8r_general_ci    |      1 |
| latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
| latin2   | ISO 8859-2 Central European     | latin2_general_ci   |      1 |
| swe7     | 7bit Swedish                    | swe7_swedish_ci     |      1 |
| ascii    | US ASCII                        | ascii_general_ci    |      1 |
| ujis     | EUC-JP Japanese                 | ujis_japanese_ci    |      3 |
| sjis     | Shift-JIS Japanese              | sjis_japanese_ci    |      2 |
| hebrew   | ISO 8859-8 Hebrew               | hebrew_general_ci   |      1 |
| tis620   | TIS620 Thai                     | tis620_thai_ci      |      1 |
| euckr    | EUC-KR Korean                   | euckr_korean_ci     |      2 |
| koi8u    | KOI8-U Ukrainian                | koi8u_general_ci    |      1 |
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
| greek    | ISO 8859-7 Greek                | greek_general_ci    |      1 |
| cp1250   | Windows Central European        | cp1250_general_ci   |      1 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
| latin5   | ISO 8859-9 Turkish              | latin5_turkish_ci   |      1 |
| armscii8 | ARMSCII-8 Armenian              | armscii8_general_ci |      1 |
| utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |
| ucs2     | UCS-2 Unicode                   | ucs2_general_ci     |      2 |
| cp866    | DOS Russian                     | cp866_general_ci    |      1 |
| keybcs2  | DOS Kamenicky Czech-Slovak      | keybcs2_general_ci  |      1 |
| macce    | Mac Central European            | macce_general_ci    |      1 |
| macroman | Mac West European               | macroman_general_ci |      1 |
| cp852    | DOS Central European            | cp852_general_ci    |      1 |
| latin7   | ISO 8859-13 Baltic              | latin7_general_ci   |      1 |
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_general_ci  |      4 |
| cp1251   | Windows Cyrillic                | cp1251_general_ci   |      1 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
| utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
| cp1256   | Windows Arabic                  | cp1256_general_ci   |      1 |
| cp1257   | Windows Baltic                  | cp1257_general_ci   |      1 |
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
| binary   | Binary pseudo charset           | binary              |      1 |
| geostd8  | GEOSTD8 Georgian                | geostd8_general_ci  |      1 |
| cp932    | SJIS for Windows Japanese       | cp932_japanese_ci   |      2 |
| eucjpms  | UJIS for Windows Japanese       | eucjpms_japanese_ci |      3 |
| gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set
```

MySQL中的默认字符集是`latin1`。如果要在单列中存储多种语言的字符，可以使用`Unicode`字符集，即`utf8`或`ucs2`。

`Maxlen`列中的值指定字符集中的字符持有的字节数。一些字符集包含单字节字符，例如：`latin1`，`latin2`，`cp850`等，而其他字符集包含多字节字符。

MySQL提供了`LENGTH`函数来获取字节的长度，以字节为单位，`CHAR_LENGTH`函数用于获取字符串的长度。如果字符串包含多字节字符，则`LENGTH`函数的结果大于`CHAR_LENGTH()`函数的结果。 请参阅以下示例：

```sql
SET @str = CONVERT('我的MySQL' USING ucs2);

SELECT LENGTH(@str), CHAR_LENGTH(@str);、
```

执行上面查询，得到以下结果 -

```sql
+--------------+-------------------+
| LENGTH(@str) | CHAR_LENGTH(@str) |
+--------------+-------------------+
|           14 |                 7 |
+--------------+-------------------+
1 row in set
```

`CONVERT`函数将字符串转换为指定的字符集。在这个例子中，它将MySQL字符集字符串的字符集转换为`ucs2`。 因为`ucs2`字符集包含`2`个字节的字符，因此`@str`字符串的长度(以字节为单位)大于其字符长度。

请注意，某些字符集包含多字节字符，但其字符串可能只包含单字节字符，例如`utf8`，如以下语句所示：

```sql
SET @str = CONVERT('MySQL Character Set' USING utf8);
SELECT LENGTH(@str), CHAR_LENGTH(@str);
```

执行上面查询语句，得到以下结果 -

```sql
+--------------+-------------------+
| LENGTH(@str) | CHAR_LENGTH(@str) |
+--------------+-------------------+
|           19 |                19 |
+--------------+-------------------+
1 row in set
```

但是，如果`utf8`字符串包含特殊字符，例如`ü`在`pingüino`字符串中; 其字节长度不同，请参见以下示例：

```sql
SET @str = CONVERT('pingüino' USING utf8);
SELECT LENGTH(@str), CHAR_LENGTH(@str);
```

执行上面查询语句，得到以下结果 -

```sql
+--------------+-------------------+
| LENGTH(@str) | CHAR_LENGTH(@str) |
+--------------+-------------------+
|            9 |                 8 |
+--------------+-------------------+
1 row in set
```

一个使用中文的示例 -

```sql
SET @str = CONVERT('不要问我有多长' USING utf8);
SELECT LENGTH(@str), CHAR_LENGTH(@str);
```

执行上面查询语句，得到以下结果 -

```sql
+--------------+-------------------+
| LENGTH(@str) | CHAR_LENGTH(@str) |
+--------------+-------------------+
|           21 |                 7 |
+--------------+-------------------+
1 row in set
```

在使用`utf8`字符集编码时，中文字占`3`个长度。

## 转换不同的字符集

MySQL提供了两个函数，允许您在不同字符集之间转换字符串：`CONVERT`和`CAST`。 在上面的例子中，我们多次使用了`CONVERT`函数。

`CONVERT`函数的语法如下：

```sql
CONVERT(expression USING character_set_name)
```

CAST函数类似于`CONVERT`函数。它将字符串转换为不同的字符集：

```sql
CAST(string AS character_type CHARACTER SET character_set_name)
```

看一下使用`CAST`函数的以下示例：

```sql
SELECT CAST(_latin1'MySQL character set' AS CHAR CHARACTER SET utf8);
```

执行上面查询语句，得到以下结果 -

```sql
+---------------------------------------------------------------+
| CAST(_latin1'MySQL character set' AS CHAR CHARACTER SET utf8) |
+---------------------------------------------------------------+
| MySQL character set                                           |
+---------------------------------------------------------------+
1 row in set
```

## 设置客户端连接的字符集

当应用程序与MySQL数据库服务器交换数据时，默认字符集为`latin1`。 但是，如果数据库在`utf8`字符集中存储Unicode字符串，则使用应用程序中的`latin1`字符集将是不够的。 因此，当连接到MySQL数据库服务器时，应用程序需要指定正确的字符集。

要配置客户端连接的字符集，可以执行以下方式之一：

* 客户端连接到MySQL数据库服务器后发出`SET NAME`语句。 例如，要设置Unicode字符集`utf8`，请使用以下语句：

  ```sql
  SET NAMES 'utf8';
  ```
* 如果应用程序支持`--default-character-set`选项，则可以使用它来设置字符集。 例如，mysql客户端工具支持`--default-character-set`，您可以在配置文件中进行如下设置：

  ```
  [mysql]
  default-character-set=utf8
  ```
* 一些MySQL连接器允许您设置字符集，例如，如果您使用*PHP PDO*，则可以按如下方式设置数据源名称中的字符集：

  ```sql
  $dsn ="mysql:host=$host;dbname=$db;charset=utf8";
  ```

无论使用哪种方式，请确保应用程序使用的字符集与存储在MySQL数据库服务器中的字符集匹配。

在本教程中，您已经了解了MySQL字符集，如何在字符集之间转换字符串以及如何为客户端连接配置正确的字符集。
