问题分析

普通的字符串或者表情都是占位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。