mysql存储不了中文字符串是数据库使用中非常常见的问题,通常和字符集配置相关,只要理清字符集的作用层级和配置逻辑,就能快速解决这个问题。

问题常见表现
当mysql无法存储中文字符串时,一般会出现以下几种情况:
- 插入中文数据时报错,提示非法字符或者字段值超出范围
- 中文数据能插入,但查询出来是乱码,显示为问号或者其他无意义字符
- 部分中文可以存储,部分生僻字无法存储,比如emoji或者罕见汉字
问题核心原因
mysql存储中文需要字符集支持,常见的问题原因主要有三类:
1. 字符集不支持中文
如果数据库、表或者字段使用了latin1这类不支持中文的字符集,中文数据就无法正常存储,这是最常见的原因。
2. 字符集配置不一致
mysql的字符集配置分为多个层级:服务端字符集、数据库字符集、表字符集、字段字符集、客户端连接字符集。如果这几个层级的字符集不一致,就会出现乱码或者存储失败的问题。
3. 字符集范围不足
早期常用的utf8字符集在mysql中实际是utf8mb3,只支持最多3个字节的字符,无法存储需要4个字节的生僻字和emoji表情,也会出现存储失败的情况。
解决方案
1. 修改数据库默认字符集
如果是新搭建的mysql环境,建议直接修改配置文件,设置默认字符集为utf8mb4,避免后续出现中文存储问题。修改mysql的配置文件my.cnf(windows系统是my.ini),在对应节点添加以下配置:
[mysqld] # 服务端默认字符集 character-set-server=utf8mb4 # 服务端默认排序规则 collation-server=utf8mb4_general_ci [client] # 客户端默认字符集 default-character-set=utf8mb4 [mysql] # mysql命令行客户端默认字符集 default-character-set=utf8mb4
修改完成后重启mysql服务即可生效。
2. 修改已有数据库、表、字段的字符集
如果已经存在数据库和表,需要单独修改对应的字符集,执行以下sql语句即可:
修改数据库字符集:
-- 修改数据库字符集和排序规则 ALTER DATABASE 数据库名 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
修改表的字符集:
-- 修改表字符集,同时转换已有字段的字符集 ALTER TABLE 表名 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
如果只需要修改单个字段的字符集:
-- 修改指定字段的字符集,需要保留原有字段类型和约束 ALTER TABLE 表名 MODIFY COLUMN 字段名 VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
3. 确保客户端连接字符集正确
很多时候数据库和表的字符集已经正确,但是客户端连接的时候没有指定正确的字符集,也会导致中文存储失败。在建立连接的时候需要指定字符集为utf8mb4,以jdbc连接为例:
// jdbc连接url中指定字符集 String url = "jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=utf8mb4";
如果是使用mysql命令行连接,可以在连接命令中指定字符集:
mysql -h 127.0.0.1 -u root -p --default-character-set=utf8mb4
验证配置是否生效
完成配置修改后,可以通过以下sql语句验证各层级的字符集是否正确:
-- 查看服务端字符集配置 SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%'; -- 查看指定数据库的字符集 SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '数据库名'; -- 查看指定表的字符集 SHOW TABLE STATUS FROM 数据库名 LIKE '表名';
如果查询到的字符集都是utf8mb4,排序规则是utf8mb4_general_ci或者对应的utf8mb4排序规则,说明配置已经生效,此时再插入中文数据就可以正常存储了。
注意事项
- 不要使用mysql中的
utf8字符集,因为它实际是utf8mb3,不支持4字节字符,优先使用utf8mb4 - 修改已有表的字符集时,
CONVERT TO CHARACTER SET语句会自动转换已有字段的字符集,不需要单独修改每个字段 - 如果表中已经有大量数据,修改字符集的操作可能会锁表,建议在业务低峰期执行