MySQL 存储 emoji 报错,怎么解决?
问题描述
在特定业务场景(帖子、评论、个人签名)存储 emoji 表情。如果使用 utf8
字符集存储,会抛出如下错误:java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for column 'name' at row 1
原因分析
MySQL 的 utf8
编码最多支持 3 个字节,而 emoji 表情需要占用 4 个字节,在早期的版本并没有实现真正意义上的 utf8
字符集。MySQL 从 5.5.3
版本开始支持 utf8mb4
字符集。
解决方案
备选方案 | 改造点 | 优缺点 |
---|---|---|
把 utf8 编码改为 utf8mb4 |
客户端修改会话字符集 服务端调整相关库表的字符集 |
更改大数据表困难 |
写入数据时编码,读取数据时解码还原 | 程序对每一个需要处理的字段进行修改,工作量不可控 | 不用修改生产数据库,DB 可读性差,额外性能消耗 |
正常情况下,我们会选择前者来解决这个问题。
- 查看 MySQL 服务端的字符集,确认是否为
utf8mb4
。
1 | SHOW VARIABLES WHERE VARIABLE_NAME LIKE 'character_set_database' OR VARIABLE_NAME LIKE 'collation%'; |
如果不是,进行调整,调整 MySQL 的配置文件,内容如下。
1 | [client] |
重启 MySQL Server,重新确认 MySQL 服务端的字符集是否修改成功。
- 调整 JDBC 连接串,不配置 characterEncoding 选项,让 MySQL 连接器选择服务端的字符集。
1 | jdbc:mysql://localhost:3306/db?useUnicode=true&&zeroDateTimeBehavior=convertToNull&autoReconnect=true |
- 检查客户端代码的会话字符集。有些云数据库的环境并不支持配置
character-set-client-handshake
或者init_connect
这样的参数。您可以通过set names utf8mb4;
命令将character_set_client
、character_set_connection
、character_set_results
等会话字符集相设置为utf8mb4
,以保证写入或者读出的数据使用utf8mb4
字符集进行处理。例如 HikariCP 数据库连接池框架,在应用的配置项加上相关参数。
1 | spring: |
- 修改历史数据的字符集。对于存储了字符编码为
utf8
的历史数据,如果要支持utf8mb4
,需要将已经存在的数据库、表、列的类型修改成utf8mb4
。首先,我们先调整数据库的默认字符集。
1 | ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; |
MySQL 支持您修改表或者列的字符集。修改 Table 的字符集示例如下:
1 | ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; |
如果您不希望修改整个表的字符集,可以选择指定 Column 进行调整。
1 | ALTER TABLE <table_name> MODIFY COLUMN <column_name> VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; |
本博客所有文章除特别声明外,均采用 Apache 2.0 License 许可协议。转载请注明来自 梦想歌の网络日志!