mysql
存储汉字遇到的问题。
有的汉字不能存储
环境
- python3.7
- mysql 8.0.17
- macos
- 编码:utf8
有的汉字是生僻字,所以,存储的时候会出现
pymysql.err.InternalError: (1366, “Incorrect string value:
原因
UTF-8
编码有可能是两个、三个、四个字节。Emoji表情、生僻字是4个字节,而Mysql
的utf8
编码最多3个字节,所以数据插不进去。
需要改变数据库的编码方式,选择 utf8mb4
。
utf8 和 utf8mb4 区别
MySQL
在 5.5.3
之后增加了 utf8mb4
字符编码,mb4
即 most bytes 4
。简单说 utf8mb4
是 utf8
的超集并完全兼容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
把ß
、Œ
当成ss
和OE
来看;而general
会把它们当成s
、e
,再如ÀÁÅåāă
各自都与 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 | drop table IF EXISTS `t_introductions`; |
还有 python
代码。
1 | import pymysql |
最后成功存储。