概述
中文乱码是我们日常编程开发中经常会遇到的问题,包括:
- 浏览器(页面)显示乱码,参考记一次中文乱码排查解决流程
- Linux系统字体缺失导致中文乱码,参考Linux环境下Selenium截图乱码及字体安装及与字符集区别
- IDEA console控制台乱码,参考IDEA + Tomcat 8.5中文乱码解决过程
- 数据库中文乱码,
- CSV/Excel文件中文乱码,参考BOM及CSV/Excel乱码及从代码上根源解决问题
本文就是一次数据库中文乱码问题记录。
问题
一个很简单的CRUD接口,Postman模拟接口前端传参JSON如下(省略其他字段):
{
"companyName": "以邑妈测试的公司"
}
接口自是请求成功,去DataGrip里查看一下数据库,发现乱码:
8个英文?
符号,正好对应以邑妈测试的公司
中文字符长度。
注,这个表是业务开发时,新增的表。
排查
首先检查当前数据库,其他表里也有中文信息,没有乱码。发现同一个数据库下另一个表结构定义语句如下(省略其他无关信息):
comment '信息表' charset = utf8mb4;
charset
理论上,表结构默认就是UTF-8编码,utf8mb4是UTF-8的增强版。也就是说,这个表结构编码定义可加可不加。
问题已经发生,在不知道解决方案时,总是会如盲头苍蝇诸般尝试。于是修改数据表编码
alter table merchant_app convert to character set utf8mb4;
不行,还是乱码!
character_set
Google搜索,看了不下5篇文档,都说和character_set
有关。于是查询字符集:
show variables like '%char%';
输出:
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 | latin1 |
character_set_system | utf8 |
character_sets_dir | /usr/share/mysql/charsets/ |
其中character_set_server=latin1
,看起来就是问题所在。
但是:数据库是已经安装并配置好,是不是最优配置,此时讨论意义不大;数据库不是只有我新增的这一个表,其他表可以正常存储中文数据。
所以绝大多数文章推荐的解决方案:修改MySQL全局配置文件my.ini
里的character_set_server=utf8
配置项,并重启数据库,就显得有些无厘头。如果是自己本机安装的数据库,搭建本地demo测试项目,出现中文乱码,我们可以放心大胆修改全局配置,并重启数据库。
DataGrip
考虑到上面的中文乱码是Java应用程序通过mysql-connector-java
JDBC驱动连接数据库,通过socket提交SQL时才会出现中文乱码。
那我在DataGrip客户端执行提交SQL试试呢?
UPDATE merchant_app SET company_name = '中文' WHERE id = 1;
结果:
是正常的!没有乱码!!貌似看到希望的曙光。
此时我们再去看看DataGrip的DataSource配置详情看看,在General里URL平平无奇,指定IP和端口。
进一步查看Advanced便签页:
也就是说DataGrip默认帮我们在URL里增加characterEncoding=UTF-8
配置信息。
如果手动修改这个配置项,也就是上面那个character_set_server=latin1
此时再次执行上面的SQL:
UPDATE merchant_app SET company_name = '中文' WHERE id = 1;
结果:
结论
修改JDBC connection String,这个配置在yml
文件里。之前使用的是jdbc:mysql://10.20.30.40:3306/user
,更新为jdbc:mysql://10.20.30.40:3306/user?useUnicode=true&characterEncoding=UTF-8
,即可解决问题。
拓展
安装
DBA在安装好MySQL数据库后,需要做一些配置,其中就包括设置character_set_server=utf8
或character_set_server=utf8mb4
。如果有这项配置,在Java应用程序里连接MySQL数据库,即,在Client端连接时,就不需要显式指定characterEncoding=UTF-8
,因为此时有MySQL Server端的character_set_server
配置给予保证不会出现中文乱码。
如果Server端没有做好调优(事实上,这个算是基础配置,还谈不上调优配置)配置,那就必须在Client端加上characterEncoding
配置。
UTF-8 & utf8mb4
MySQL 5.5.3后增加utf8mb4编码,mb4即most bytes 4,用于兼容四字节的unicode。utf8mb4是utf8的超集。