问题分析
- 普通的字符串或者表情都是占位3个字节,所以utf8足够用了,但是移动端的表情符号占位是4个字节,普通的utf8就不够用了,为了应对无线互联网的机遇和挑战、避免 emoji 表情符号带来的问题、涉及无线相关的 MySQL 数据库建议都提前采用 utf8mb4 字符集,这必须要作为移动互联网行业的一个技术选型的要点
- Mysql 版本的限制,Mysql 5.5.3之前的版本,支持的utf8为3字节的,Mysql 5.5.3之后的版本支持utf8mb4
解决方案
首先我们看下哪些地方可能需要我们修改编码:
- 库(database)的编码
- 表(table)的编码
- 字段(column)的编码
- 程序中,数据库的连接url
- mysql的配置文件my.conf中
我们可以先查询下当前数据库的编码信息:
SHOW VARIABLES LIKE 'character_set_%'
Variable_name | Value |
---|---|
character_set_client | utf8 |
character_set_connection | utf8 |
character_set_database | utf8 |
character_set_filesystem | binary |
character_set_results | utf8 |
character_set_server | utf8 |
character_set_system | utf8 |
character_sets_dir | /opt/install/mysql/share/charsets/ |
我们将库的编码修改
datebase charset=utf8mb4
datebase collation=utf8mb4_unicode_ci
将表的编码修改
character set=utf8mb4
collation=utf8mb4_unicode_ci
将需要支持emoji表情字段的编码修改
Charset=utf8mb4
Collation=utf8mb4_unicode_ci
修改mysql的配置文件my.conf
[client]
# 客户端来源数据的默认字符集
default-character-set = utf8mb4
[mysql]
# 数据库默认字符集
default-character-set = utf8mb4
[mysqld]
# 服务端默认字符集
character-set-server=utf8mb4
# 连接层默认字符集
collation-server=utf8mb4_unicode_ci
修改完毕后,记得重新启动mysql服务
/etc/init.d/mysql restart
修改后,刷新连接后查看相关变量:
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 | /opt/install/mysql/share/charsets/ |
实测:修改项目中的连接数据库的url,将characterEncoding=utf-8
去掉,实测此步骤可以不用改变。
字符集知识扩展
- 字符集、连接字符集、排序字符集
utf8mb4对应的排序字符集有utf8mb4_unicode_ci、utf8mb4_general_ci.
- utf8mb4_unicode_ci和utf8mb4_general_ci的对比:
准确性:
- utf8mb4_unicode_ci是基于标准的Unicode来排序和比较,能够在各种语言之间精确排序
- utf8mb4_general_ci没有实现Unicode排序规则,在遇到某些特殊语言或者字符集,排序结果可能不一致。
- 但是,在绝大多数情况下,这些特殊字符的顺序并不需要那么精确。
性能
- utf8mb4_general_ci在比较和排序的时候更快
- utf8mb4_unicode_ci在特殊情况下,Unicode排序规则为了能够处理特殊字符的情况,实现了略微复杂的排序算法。
- 但是在绝大多数情况下发,不会发生此类复杂比较。相比选择哪一种collation,使用者更应该关心字符集与排序规则在db里需要统一。
至于排序规则(collation) 选择默认的 utf8mb4_general_ci,还是 utf8mb4_unicode_ci。 请参考stack overflow的这篇帖子。 讨论结果从排序的准确性,以及性能方面,告诉我们应该选用 utf8mb4_unicode_ci。