0%

mysql | 存储汉字

mysql 存储汉字遇到的问题。

有的汉字不能存储

环境

  • python3.7
  • mysql 8.0.17
  • macos
  • 编码:utf8

有的汉字是生僻字,所以,存储的时候会出现

pymysql.err.InternalError: (1366, “Incorrect string value:

原因

UTF-8编码有可能是两个、三个、四个字节。Emoji表情、生僻字是4个字节,而Mysqlutf8编码最多3个字节,所以数据插不进去。

需要改变数据库的编码方式,选择 utf8mb4

utf8 和 utf8mb4 区别

MySQL5.5.3 之后增加了 utf8mb4 字符编码,mb4most bytes 4。简单说 utf8mb4utf8 的超集并完全兼容utf8,能够用四个字节存储更多的字符。

也就是当你的数据库里要求能够存入这些表情或宽字符时,可以把字段定义为 utf8mb4,同时要注意连接字符集也要设置为utf8mb4,否则在 严格模式 下会出现 Incorrect string value: /xF0/xA1/x8B/xBE/xE5/xA2… for column 'name' 这样的错误,非严格模式下此后的数据会被截断。

utf8mb4unicodeci 与 utf8mb4generalci 如何选择

字符除了需要存储,还需要排序或比较大小,涉及到与编码字符集对应的 排序字符集(collation)。ut8mb4对应的排序字符集常用的有

  • utf8mb4_unicode_ci
  • utf8mb4_general_ci

主要从排序准确性和性能两方面看:

  • 准确性

utf8mb4_unicode_ci 是基于标准的 Unicode来排序和比较,能够在各种语言之间精确排序。

utf8mb4_general_ci 没有实现Unicode排序规则,在遇到某些特殊语言或字符是,排序结果可能不是所期望的。

但是在绝大多数情况下,这种特殊字符的顺序一定要那么精确吗。比如Unicodeߌ当成ssOE来看;而general会把它们当成se,再如ÀÁÅåāă各自都与 A 相等。

  • 性能

utf8mb4_general_ci 在比较和排序的时候更快。

utf8mb4_unicode_ci 在特殊情况下,Unicode排序规则为了能够处理特殊字符的情况,实现了略微复杂的排序算法。

但是在绝大多数情况下,不会发生此类复杂比较。general理论上比Unicode可能快些,但相比现在的CPU来说,它远远不足以成为考虑性能的因素,索引涉及、SQL设计才是。

原作者推荐的是 utf8mb4_unicode_ci

进入 mysql 环境,输入

show variables like 'character%';

我最开始出现,看 character_set_database

+--------------------------+-----------------------------------------------------------+
| Variable_name            | Value                                                     |
+--------------------------+-----------------------------------------------------------+
| character_set_client     | utf8mb4                                                   |
| character_set_connection | utf8mb4                                                   |
| character_set_database   | utf8                                                      |
| character_set_filesystem | binary                                                    |
| character_set_results    | utf8mb4                                                   |
| character_set_server     | utf8mb4                                                   |
| character_set_system     | utf8                                                      |
| character_sets_dir       | /usr/local/mysql-8.0.17-macos10.14-x86_64/share/charsets/ |
+--------------------------+-----------------------------------------------------------+

更改数据库的编码。

set character_set_database=utf8mb4;

然后执行

show variables like 'character%';

出现

+--------------------------+-----------------------------------------------------------+
| Variable_name            | Value                                                     |
+--------------------------+-----------------------------------------------------------+
| character_set_client     | utf8mb4                                                   |
| character_set_connection | utf8mb4                                                   |
| character_set_database   | utf8mb4                                                   |
| character_set_filesystem | binary                                                    |
| character_set_results    | utf8mb4                                                   |
| character_set_server     | utf8mb4                                                   |
| character_set_system     | utf8                                                      |
| character_sets_dir       | /usr/local/mysql-8.0.17-macos10.14-x86_64/share/charsets/ |
+--------------------------+-----------------------------------------------------------+

然后可以看我创建的表规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
drop table IF EXISTS `t_introductions`;
create TABLE `t_introductions` (
`id` bigint(21) NOT NULL AUTO_INCREMENT,
`author` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名称',
`title` varchar(32) NOT NULL DEFAULT '' COMMENT '文章标题',
`img` TEXT COMMENT '图片',
`description` TEXT COMMENT '文章摘要',
`content` LONGTEXT COMMENT '文章内容',
`type` tinyint(4) NOT NULL COMMENT '文章类型',
`status` tinyint(4) DEFAULT 1 COMMENT '文章状态',
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`utime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

还有 python 代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pymysql
from DBUtils.PooledDB import PooledDB
import app_config as config

database = PooledDB(
pymysql,
5,
host=**
user=**
passwd=**
db=**
port=**
charset="utf8mb4"
)

最后成功存储。

请我喝杯咖啡吧~