简短回答: 是的,如果您只使用 3 字节(或更短)的 UTF-8 字符。
或者... 否,如果您打算使用 4 字节 UTF-8 字符,例如 ???。
长答案:
(我将解释为什么“不”可能是正确答案。)
连接确定客户端正在使用什么编码。
列上的CHARACTER SET(或默认情况下,来自表)确定可以将什么编码放入列中。
CHARACTER SET utf8 是utf8mb4 的子集。也就是说,utf8(通过连接或列)可以接受的所有字符都可以为utf8mb4 接受。换句话说,MySQL 的utf8mb4(与外界的UTF-8 相同)具有完整的 4 字节 utf-8 编码,比 MySQL 最多 3 字节的 utf8 包含更多的 Emoji、更多的中文等(又名“BMP”)
(从技术上讲,utf8mb4 最多只能处理 4 个字节,但UTF-8 可以处理更长的字符。但是,我怀疑在我的一生中是否会出现 5 个字节的字符。)
因此,假设连接为 utf8mb4 且表中的列仅为 utf8,则客户端中任何 3 字节(或更短)的 UTF-8 字符会发生以下情况:每个字符都进出服务器没有转换,没有错误。注意:问题出现在INSERT,而不是SELECT;但是,在您执行SELECT 之前,您可能不会注意到问题。
但是,如果您在客户端中有表情符号怎么办?现在你会得到一个错误。 (或截断的字符串)(或问号)这是因为 4 字节的 Emoji(例如?)无法压缩到 3 字节的“utf8”(或“1 字节 latin1”或... )。
如果您运行的是 5.5 或 5.6,您可能会遇到 767(或 191)问题。我在here 中提供了几种解决方法。没有一个是完美的。
至于反转(utf8 连接但 utf8mb4 列):如果您设法将一些 4 字节字符放入表中,SELECT 可能会遇到麻烦。
“官方来源”——祝你好运。我花了十年时间试图梳理字符处理的来龙去脉,然后将其简化为可操作的句子。大部分时间都在想我有所有的答案,结果却遇到了另一个失败的测试用例。常见情况在Trouble with UTF-8 characters; what I see is not what I stored 中列出。但是,这并不能直接解决您的问题!
来自评论
mysql> SHOW CREATE TABLE emoji\G
*************************** 1. row ***************************
Table: emoji
Create Table: CREATE TABLE `emoji` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`text` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
mysql> insert into emoji (text) values ("abc");
Query OK, 1 row affected (0.01 sec)
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
上面说“连接”(认为“客户端”)使用的是 utf8,而不是 utf8mb4。
mysql> insert into emoji (text) values ("???"); -- 4-byte Emoji
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+----------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------------------------------------------------+
| Warning | 1366 | Incorrect string value: '\xF0\x9F\x98\x85\xF0\x9F...' for column 'text' at row 1 |
+---------+------+----------------------------------------------------------------------------------+
1 row in set (0.00 sec)
现在,将“连接”更改为utf8mb4:
mysql> SET NAMES utf8mb4;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into emoji (text) values ("???");
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM emoji;
+----+--------------+
| id | text |
+----+--------------+
| 1 | ? ? ? ? |
| 2 | abc |
| 3 | ???????????? | -- from when "utf8" was in use
| 4 | ??? | -- Success with utf8mb4 in use
+----+--------------+
4 rows in set (0.01 sec)