A.11.1. |
MySQL 中有哪些 CJK 字符集可用? |
|
CJK 字符集列表可能取决于您的 MySQL 版本。例如,gb18030 字符集在 MySQL 5.7.4 之前不受支持。然而,由于适用语言的名称出现在 DESCRIPTION 列中,每个条目在 INFORMATION_SCHEMA.CHARACTER_SETS 表中,因此您可以使用以下查询获取所有非 Unicode CJK 字符集的当前列表:
mysql> SELECT CHARACTER_SET_NAME, DESCRIPTION
FROM INFORMATION_SCHEMA.CHARACTER_SETS
WHERE DESCRIPTION LIKE '%Chin%'
OR DESCRIPTION LIKE '%Japanese%'
OR DESCRIPTION LIKE '%Korean%'
ORDER BY CHARACTER_SET_NAME;
+--------------------+---------------------------------+
| CHARACTER_SET_NAME | DESCRIPTION |
+--------------------+---------------------------------+
| big5 | 传统中文 Big5 |
| cp932 | Windows 日语 SJIS |
| eucjpms | Windows 日语 UJIS |
| euckr | 韩文 EUC-KR |
| gb18030 | 中国国家标准 GB18030 |
| gb2312 | 简体中文 GB2312 |
| gbk | 简体中文 GBK |
| sjis | 日语 Shift-JIS |
| ujis | 日语 EUC-JP |
+--------------------+---------------------------------+
(更多信息,请参阅 第 28.3.4 节,“INFORMATION_SCHEMA CHARACTER_SETS 表”。)
MySQL 支持三种 GB (国标,或 国家标准,或 简体中文) 字符集,它们是中国人民共和国的官方标准:gb2312 、gbk ,以及(从 MySQL 5.7.4 开始)gb18030 。
有时人们尝试将 gbk 字符插入 gb2312 ,并且大多数情况下都能工作,因为 gbk 是 gb2312 的超集。但是,最后他们尝试插入一个罕见的中文字符时就会失败。(例如,参阅 Bug #16072)。
在这里,我们尝试明确地说明 gb2312 或 gbk 中的合法字符,以官方文档为参考。请在报告 gb2312 或 gbk 错误之前检查这些参考:
也可以在 Unicode 字符集中存储 CJK 字符,尽管可用的排序可能不会像您期望的那样排序:
Unicode 字符集的排序取决于所用的排序规则:
-
基于 Unicode 排序算法(UCA)4.0.0 的排序规则仅区分 BMP 字符。
-
基于 UCA 5.2.0 或 9.0.0 的排序规则区分 BMP 和补充字符。
-
非 UCA 排序规则可能不区分所有 Unicode 字符。例如,utf8mb4 的默认排序规则是 utf8mb4_general_ci ,它仅区分 BMP 字符。
此外,区分字符与根据给定CJK语言的惯例对它们进行排序不同。目前,MySQL只有一个CJK特定的UCA排序规则:gb18030_unicode_520_ci (需要使用非Unicode gb18030 字符集)。
有关Unicode排序规则及其区分属性的信息,包括补充字符的排序规则属性,请参阅 第 12.10.1 节,“Unicode 字符集”。 |
A.11.2. |
我已经将CJK字符插入到我的表中。为什么SELECT 将它们显示为“?”字符? |
|
这种问题通常是由于MySQL中的设置与应用程序或操作系统的设置不匹配。以下是一些常见的解决这些问题的步骤:
-
确保您使用的是哪个MySQL版本。
使用语句 SELECT VERSION(); 来确定此事。
-
确保数据库实际使用的是所需的字符集。
人们经常认为客户端字符集总是与服务器字符集或显示用途的字符集相同。但是,这两种假设都是错误的。您可以通过检查 SHOW CREATE TABLE tablename 的结果来确保,或者使用以下语句:
SELECT character_set_name, collation_name
FROM information_schema.columns
WHERE table_schema = your_database_name
AND table_name = your_table_name
AND column_name = your_column_name;
-
确定无法正确显示的字符的十六进制值。
您可以使用以下查询来获取该信息,用于列 column_name 在表 table_name 中:
SELECT HEX(column_name)
FROM table_name;
3F 是 ? 字符的编码;这意味着 ? 是实际存储在列中的字符。这通常是由于将特定字符从客户端字符集转换到目标字符集时出现问题。
-
确保可以进行圆trip。当您选择 literal (或 _introducer hexadecimal-value ),您是否可以获得 literal 作为结果?
例如,日语片假名字符 Pe (ペ' ) 存在于所有 CJK 字符集中,并且具有代码点值(十六进制编码) 0x30da 。要测试该字符的圆trip,请使用以下查询:
SELECT 'ペ' AS `ペ`; /* 或 SELECT _ucs2 0x30da; */
如果结果不是也 ペ ,则圆trip失败。
对于这种失败的错误报告,我们可能会要求您跟进 SELECT HEX('ペ'); 。然后我们可以确定客户端编码是否正确。
-
确保问题不在浏览器或其他应用程序中,而是在 MySQL 中。
使用 mysql 客户端程序来完成此任务。如果 mysql 正确显示字符但您的应用程序不正确,那么您的问题可能是由于系统设置。
要确定您的设置,请使用 SHOW VARIABLES 语句,其输出应类似于以下所示:
mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------------------+
| 变量名称 | 值 |
+--------------------------+----------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+
这些是面向国际化客户端(注意使用 utf8 Unicode)的典型字符集设置,连接到西方服务器(latin1 是西欧字符集)。
虽然 Unicode(通常是 Unix 上的 utf8 变体,Windows 上的 ucs2 变体)优于 Latin,但它并不总是您的操作系统实用程序支持的最好选择。许多 Windows 用户发现 Microsoft 字符集,例如日本 Windows 的 cp932 ,非常适合。
如果您无法控制服务器设置,并且不知道您的基础计算机使用什么设置,请尝试更改为您所在国家/地区的常见字符集(euckr = 韩国;gb18030 、gb2312 或 gbk = 中国大陆;big5 = 台湾;sjis 、ujis 、cp932 或 eucjpms = 日本;ucs2 或 utf8 = 任何地方)。通常只需要更改客户端和连接和结果设置。SET NAMES 语句可以同时更改三个设置。例如:
SET NAMES 'big5';
一旦设置正确,您可以通过编辑 my.cnf 或 my.ini 使其永久化。例如,您可能添加以下行:
[mysqld]
character-set-server=big5
[client]
default-character-set=big5
也可能是您的应用程序中的 API 配置设置问题;请参阅 为什么我的 GUI 前端或浏览器不能正确显示 CJK 字符...? 以获取更多信息。
|
A.11.3. |
使用 Big5 中文字符集时需要注意什么问题? |
|
MySQL 支持 Big5 字符集,该字符集在香港和台湾(中华民国)很常见。MySQL 的 big5 字符集实际上是 Microsoft 代码页 950,与原始的 big5 字符集非常相似。
已经提交了添加 HKSCS 扩展的功能请求。需要该扩展的人可能会对 Bug #13577 的补丁感兴趣。 |
A.11.4. |
为什么日文字符集转换会失败? |
|
MySQL支持sjis 、ujis 、cp932 和eucjpms 字符集,以及Unicode。一个常见的需求是之间的字符集转换。例如,可能有一个 Unix 服务器(通常使用sjis 或ujis )和一个 Windows 客户端(通常使用cp932 )。
在以下转换表中,ucs2 列代表源,而sjis 、cp932 、ujis 和eucjpms 列代表目标;也就是说,最后 4 列提供了使用CONVERT(ucs2) 或将ucs2 列中的值分配给sjis 、cp932 、ujis 或eucjpms 列时的十六进制结果。
现在考虑以下表的一部分。
这意味着 MySQL 将 NOT SIGN (Unicode U+00AC ) 转换为 sjis 代码点 0x81CA 和 cp932 代码点 3F 。(3F 是问号 (“?”。这是在无法执行转换时总是使用的。) |
Here is the translated HTML fragment:
A.11.5. |
如果我想将SJIS 81CA 转换为 cp932 ,我该怎么做? |
|
我们的回答是:“?””。这有缺点,许多人更喜欢松散的转换,以便SJIS中的 81CA (NOT SIGN) 变为 cp932 中的 81CA (FULLWIDTH NOT SIGN) 。 |
A.11.6. |
MySQL如何表示日元符号(¥ )? |
|
出现问题,因为一些日本字符集版本(包括 sjis 和 euc )将 5C 视为反斜杠(\ ,也称为反斜杠),而其他版本将其视为日元符号(¥ )。
MySQL遵循JIS(日本工业标准)标准描述。在MySQL中,5C 始终是反斜杠(\ )。 |
A.11.7. |
在MySQL中使用韩文字符集时,我需要注意什么问题? |
|
理论上,虽然有多个版本的 euckr (扩展Unix代码韩国)字符集,但只有一个问题被注意到。我们使用 “ASCII” 变体的EUC-KR,其中代码点 0x5c 是反斜杠,即 \ ,而不是 “KS-Roman” 变体的EUC-KR,其中代码点 0x5c 是韩元符号(₩ )。这意味着您不能将Unicode U+20A9 转换为 euckr :
mysql> SELECT
CONVERT('₩' USING euckr) AS euckr,
HEX(CONVERT('₩' USING euckr)) AS hexeuckr;
+-------+----------+
| euckr | hexeuckr |
+-------+----------+
| ? | 3F |
+-------+----------+
|
A.11.8. |
为什么我会收到 Incorrect string value 错误信息? |
|
要查看问题,请创建一个表,其中一个 Unicode(ucs2 )列和一个中文(gb2312 )列。
mysql> CREATE TABLE ch
(ucs2 CHAR(3) CHARACTER SET ucs2,
gb2312 CHAR(3) CHARACTER SET gb2312);
在非严格 SQL 模式下,尝试将罕见字符 汌 放入两个列中。
mysql> SET sql_mode = '';
mysql> INSERT INTO ch VALUES ('A汌B','A汌B');
Query OK, 1 row affected, 1 warning (0.00 sec)
INSERT 语句产生了警告。使用以下语句来查看它是什么:
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Warning
Code: 1366
Message: Incorrect string value: '\xE6\xB1\x8CB' for column 'gb2312' at row 1
因此,它是一个关于 gb2312 列的警告。
mysql> SELECT ucs2,HEX(ucs2),gb2312,HEX(gb2312) FROM ch;
+-------+--------------+--------+-------------+
| ucs2 | HEX(ucs2) | gb2312 | HEX(gb2312) |
+-------+--------------+--------+-------------+
| A汌B | 00416C4C0042 | A?B | 413F42 |
+-------+--------------+--------+-------------+
这里有几件事需要解释:
-
汌 字符不在 gb2312 字符集中,如前所述。
-
如果您使用的是旧版本的 MySQL,您可能会看到不同的消息。
-
警告而不是错误,因为 MySQL 未设置为使用严格 SQL 模式。在非严格模式下,MySQL 尝试尽力而为,以获得最佳匹配,而不是放弃。使用严格 SQL 模式时,Incorrect string value 消息将作为错误而不是警告,并且 INSERT 将失败。
|
A.11.9. |
为什么我的 GUI 前端或浏览器在使用 Access、PHP 或另一个 API 的应用程序中无法正确显示 CJK 字符? |
|
使用 mysql 客户端直接连接到服务器,并尝试相同的查询。如果 mysql 正确响应,问题可能是您的应用程序接口需要初始化。使用 mysql 告诉您它使用的字符集或集合,使用语句 SHOW VARIABLES LIKE 'char%'; 。如果您使用 Access,您可能正在使用 Connector/ODBC 连接。在这种情况下,您应该检查 配置 Connector/ODBC。如果例如您使用 big5 ,您将输入 SET NAMES 'big5' 。(在这种情况下,不需要 ; 字符。)如果您使用 ASP,您可能需要在代码中添加 SET NAMES 。以下是一个曾经成功的示例:
<%
Session.CodePage=0
Dim strConnection
Dim Conn
strConnection="driver={MySQL ODBC 3.51 Driver};server=server;uid=username;" \
& "pwd=password;database=database;stmt=SET NAMES 'big5';"
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open strConnection
%>
同样,如果您使用 Connector/NET 连接到任何字符集,而不是 latin1 ,您必须在连接字符串中指定字符集。请参阅 Connector/NET 连接,以获取更多信息。
如果您使用 PHP,尝试以下操作:
<?php
$link = new mysqli($host, $usr, $pwd, $db);
if( mysqli_connect_errno() )
{
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$link->query("SET NAMES 'utf8'");
?>
在这种情况下,我们使用 SET NAMES 更改 character_set_client 、character_set_connection 和 character_set_results 。
在 PHP 应用程序中经常遇到的另一个问题是浏览器的假设。有时添加或更改 <meta> 标签足以解决问题:例如,要确保用户代理将页面内容解释为 UTF-8 ,请在 HTML 页面的 <head> 部分添加 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 。
如果您使用 Connector/J,请参阅 使用字符集和 Unicode。 |
A.11.10. |
我已经升级到 MySQL 8.3。如何恢复到 MySQL 4.0 中的字符集行为? |
|
在 MySQL 版本 4.0 中,有一个单一的 “全局” 字符集用于服务器和客户端,服务器管理员决定使用哪个字符集。从 MySQL 版本 4.1 开始,这种情况发生了变化。现在的情况是一个 “握手”,如 第 12.4 节,“连接字符集和排序规则” 所述:
这意味着您不能通过启动 mysqld 使用 --character-set-server=utf8 控制客户端字符集。然而,一些亚洲客户更喜欢 MySQL 4.0 的行为。为了使其能够保留这种行为,我们添加了一个 mysqld 开关,--character-set-client-handshake ,可以使用 --skip-character-set-client-handshake 关闭。如果您使用 --skip-character-set-client-handshake 启动 mysqld,那么,当客户端连接时,它会将要使用的字符集名称发送给服务器。但是,服务器将忽略客户端的请求。
例如,假设您的服务器字符集是 latin1 。假设客户端使用 utf8 ,因为这是客户端操作系统支持的。使用 latin1 作为默认字符集启动服务器:
mysqld --character-set-server=latin1
然后,使用默认字符集 utf8 启动客户端:
mysql --default-character-set=utf8
结果设置可以通过查看 SHOW VARIABLES 的输出来查看:
mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+
现在停止客户端,使用 mysqladmin 停止服务器。然后,再次启动服务器,但这次告诉它跳过握手,如下所示:
mysqld --character-set-server=utf8 --skip-character-set-client-handshake
再次使用 utf8 作为默认字符集启动客户端,然后显示结果设置:
mysql> 显示 VARIABLES LIKE 'char%';
+--------------------------+----------------------------------------+
| 变量名称 | 值 |
+--------------------------+----------------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+
如你所见,通过比较 显示 VARIABLES 的不同结果,如果使用 --skip-character-set-client-handshake 选项,服务器将忽略客户端的初始设置。 |
A.11.11. |
为什么一些 LIKE 和 FULLTEXT 搜索与 CJK 字符失败? |
|
对于 LIKE 搜索,有一个非常简单的问题与二进制字符串列类型相关,如 BINARY 和 BLOB :我们必须知道字符在哪里结束。使用多字节字符集,不同的字符可能具有不同的八位长度。例如,在 utf8 中,A 需要一个字节,但 ペ 需要三个字节,如下所示:
+-------------------------+---------------------------+
| OCTET_LENGTH(_utf8 'A') | OCTET_LENGTH(_utf8 'ペ') |
+-------------------------+---------------------------+
| 1 | 3 |
+-------------------------+---------------------------+
如果我们不知道字符串中的第一个字符在哪里结束,我们不知道第二个字符从哪里开始,在这种情况下,即使非常简单的搜索,如 LIKE '_A%' 也会失败。解决方案是使用定义为具有正确 CJK 字符集的非二进制字符串列类型。例如:mycol TEXT CHARACTER SET sjis 。或者,在比较之前将其转换为 CJK 字符集。
这也是 MySQL 无法允许不存在字符的编码的原因之一。如果它不严格地拒绝坏输入,它就不知道字符在哪里结束。
对于 FULLTEXT 搜索,我们必须知道单词在哪里开始和结束。使用西方语言,这通常不是问题,因为大多数(如果不是所有)使用易于识别的单词边界:空格字符。然而,这通常不是亚洲语言的情况。我们可以使用任意的半途措施,例如假设所有汉字符代表单词,或者(对于日本)依赖于片假名到平假名的变化由于语法结束。但是,唯一确定的解决方案需要一个综合的单词列表,这意味着我们需要在服务器中包含每种亚洲语言的词典。这根本不可行。 |
A.11.12. |
如何知道字符 X 是否在所有字符集中可用? |
|
大多数简体中文和基本非半宽日文假名字符出现在所有CJK字符集中。以下存储过程接受一个 UCS-2 Unicode字符,转换为其他字符集,并以十六进制形式显示结果。
DELIMITER //
CREATE PROCEDURE p_convert(ucs2_char CHAR(1) CHARACTER SET ucs2)
BEGIN
CREATE TABLE tj
(ucs2 CHAR(1) character set ucs2,
utf8 CHAR(1) character set utf8,
big5 CHAR(1) character set big5,
cp932 CHAR(1) character set cp932,
eucjpms CHAR(1) character set eucjpms,
euckr CHAR(1) character set euckr,
gb2312 CHAR(1) character set gb2312,
gbk CHAR(1) character set gbk,
sjis CHAR(1) character set sjis,
ujis CHAR(1) character set ujis);
INSERT INTO tj (ucs2) VALUES (ucs2_char);
UPDATE tj SET utf8=ucs2,
big5=ucs2,
cp932=ucs2,
eucjpms=ucs2,
euckr=ucs2,
gb2312=ucs2,
gbk=ucs2,
sjis=ucs2,
ujis=ucs2;
/* 如果存在转换问题,UPDATE 将产生警告。 */
SELECT hex(ucs2) AS ucs2,
hex(utf8) AS utf8,
hex(big5) AS big5,
hex(cp932) AS cp932,
hex(eucjpms) AS eucjpms,
hex(euckr) AS euckr,
hex(gb2312) AS gb2312,
hex(gbk) AS gbk,
hex(sjis) AS sjis,
hex(ujis) AS ujis
FROM tj;
DROP TABLE tj;
END//
DELIMITER ;
输入可以是任何单个 ucs2 字符,也可以是该字符的代码值(十六进制表示)。例如,从 Unicode 的 ucs2 编码和名称列表中(http://www.unicode.org/Public/UNIDATA/UnicodeData.txt),我们知道片假名字符 Pe 出现在所有 CJK 字符集中,并且其代码值是 X'30DA' 。如果我们使用这个值作为 p_convert() 的参数,结果将如下所示:
mysql> CALL p_convert(X'30DA');
+------+--------+------+-------+---------+-------+--------+------+------+------+
| ucs2 | utf8 | big5 | cp932 | eucjpms | euckr | gb2312 | gbk | sjis | ujis |
+------+--------+------+-------+---------+-------+--------+------+------+------+
| 30DA | E3839A | C772 | 8379 | A5DA | ABDA | A5DA | A5DA | 8379 | A5DA |
+------+--------+------+-------+---------+-------+--------+------+------+------+
由于没有列值是 3F (即问号字符,? ),我们知道每个转换都成功了。 |
A.11.13. |
为什么 CJK 字符串在 Unicode 中排序不正确?(I) |
|
从 MySQL 8.0 开始,可以使用 utf8mb4 字符集和 utf8mb4_ja_0900_as_cs 排序解决 CJK 排序问题。 |
A.11.14. |
为什么 CJK 字符串在 Unicode 中排序不正确?(II) |
|
从 MySQL 8.0 开始,可以使用 utf8mb4 字符集和 utf8mb4_ja_0900_as_cs 排序解决 CJK 排序问题。 |
A.11.15. |
为什么我的补充字符被 MySQL 拒绝? |
|
补充字符位于 Unicode 基本多语言平面 / 平面 0 之外。 BMP 字符具有代码点值介于 U+0000 和 U+FFFF 之间。补充字符具有代码点值介于 U+10000 和 U+10FFFF 之间。
要存储补充字符,您必须使用支持它们的字符集:
-
utf8 和 ucs2 字符集仅支持 BMP 字符。
utf8 字符集仅允许最多三个字节的 UTF-8 字符。这导致了 Bug #12600 的报告,我们将其拒绝为 “不是 bug”。使用 utf8 时,MySQL 必须截断输入字符串,以便在遇到不理解的字节时。
一种可能的解决方法是使用 ucs2 而不是 utf8 ,在这种情况下, “坏” 字符将被更改为问号。但是,不会发生截断。你也可以将数据类型更改为 BLOB 或 BINARY ,它们不执行有效性检查。
-
utf8mb4 、utf16 、utf16le 和 utf32 字符集支持 BMP 字符,以及 BMP 之外的补充字符。
|
A.11.16. |
是否应该将 “CJK” 更改为 “CJKV”? |
|
不。术语 “CJKV” (中文 Japanese Korean Vietnamese) 指的是越南字符集,其中包含汉字符(最初来自中国)。MySQL 支持使用西方字符的现代越南脚本,但不支持使用汉字符的旧越南脚本。
从 MySQL 5.6 开始,有越南排序规则的 Unicode 字符集,如 第 12.10.1 节,“Unicode 字符集” 所述。 |
A.11.17. |
MySQL 是否允许在数据库和表名中使用 CJK 字符? |
|
是。 |
A.11.18. |
哪里可以找到 MySQL 手册的中文、日文和韩文翻译? |
|
MySQL 5.6 手册的日文翻译可以从 https://dev.mysql.com/doc/ 下载。 |
A.11.19. |
哪里可以获取 MySQL 中的 CJK 和相关问题帮助? |
|
以下资源可用:
|