0%

MySQL 字符集踩坑记

环境:MySQL 5.7

现象

假设有一张表,结构如下:

1
2
3
CREATE TABLE `test` (
`a` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后插入两条数据(一条是中文括号,一条是英文括号):

1
2
INSERT INTO `test` (`a`) VALUES ('(甲)');
INSERT INTO `test` (`a`) VALUES ('(甲)');

然后大家觉得下面的语句结果如何?

1
SELECT * FROM test GROUP BY a

是不是觉得应该有两条,像下面的一样:

1
2
3
4
5
6
7
8
mysql> SELECT * FROM test;
+-----------+
| a |
+-----------+
| (甲) |
| (甲) |
+-----------+
2 rows in set (0.01 sec)

但实际上只有一条:

1
2
3
4
5
6
+-----------+
| a |
+-----------+
| (甲) |
+-----------+
1 row in set (0.01 sec)

也就是说,对于 MySQL 来说,"(甲)""(甲)" 是一样的。

但是我们明确知道,这里其中一个是中文的括号,另一个是英文的括号。

原因

utf8_unicode_ci 下,MySQL 在比较的时候,"(""(" 是一样的:

参考链接:https://stackoverflow.com/a/6602382/6048782

1
2
3
4
5
6
7
mysql> select _utf8"(" collate utf8_unicode_ci = _utf8"(" collate utf8_unicode_ci;
+-----------------------------------------------------------------------+
| _utf8"(" collate utf8_unicode_ci = _utf8"(" collate utf8_unicode_ci |
+-----------------------------------------------------------------------+
| 1 |
+-----------------------------------------------------------------------+
1 row in set (0.06 sec)

解决办法

使用 utf8mb4 字符集,因为:

1
2
3
4
5
6
7
mysql> select _utf8mb4"(" collate utf8mb4_general_ci = _utf8mb4"(" collate utf8mb4_general_ci;
+-----------------------------------------------------------------------------------+
| _utf8mb4"(" collate utf8mb4_general_ci = _utf8mb4"(" collate utf8mb4_general_ci |
+-----------------------------------------------------------------------------------+
| 0 |
+-----------------------------------------------------------------------------------+
1 row in set (0.01 sec)

也就是说,在 utf8mb4_general_ci 这种字符集下,MySQL 在进行比较的时候才能正确判断中英文括号。

修改字段的 SQL 语句

1
alter table tbl modify col varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci