MySQL解决中文编码问题

时间:2022-09-22 18:56:09

近日在使用Java(Servlet)+MySQL实现微信小程序的后台的时候,遇到了一个问题:微信小程序传过来的中文字符在入数据库的时候会变成“???”,这个问题的解决耗费了我七八个小时左右的时间,特意开篇博客来记录一下我的解决思路和流程。

1. 首先检查微信小程序发送请求时的Header是怎么写的:

header: { 'content-type':'application/x-www-form-urlencoded', },

我们的小程序仅设置了一个application/x-www-form-urlencoded,并未对字符编码格式(charset)进行设置,因此不知道微信小程序发过来的请求到底是什么编码格式的……

先来人工尝试一下……用微信小程序向服务器发起一个插入数据的请求后,在tomcat服务器的日志中找到了如下内容:

GET /dailyLife/api/habit/updatehabit?id=0&name=%E6%B5%8B%E8%AF%95Aa3&icon=4&category=1&weekday=4&token=0a6fff2b9ec2058eee0d26df51846497 HTTP/1.1

其中name参数是我在小程序端输入的中文,可以看到在未指定编码格式的时候,name参数被urlencode了……而我的Java后台的代码是把字符串按照utf-8来处理的……这就造成了编码格式的不统一(要解决这个问题,也可以通过修改小程序端来完成,即在发送请求时在头部加上charset = utf8,可参见Ya_豆芽的博客https://www.cnblogs.com/i-douya/p/8245359.html),不过我这里遇到的情况是尽量不修改小程序端代码,因此只能在服务器端来调整

2. 服务器端的Java代码调整

如果从服务器端进行调整,那么我们只需要在获取到参数之后立刻对它进行一次urldecode即可,这里可以使用Java的URLDecoder来完成,参见风漫宇的博客https://blog.csdn.net/xiazhiyu_whu/article/details/79708431

在Servlet中的体现:

String name = req.getParameter("name"); name = URLDecoder.decode(name, "UTF-8");

这样处理之后的name就是utf-8的格式了,并且不会影响到后续代码的执行(只是修改了一下变量的值而已嘛,又没改变量名字之类的……)

这里顺带一提:由Java官方文档可知,URLDecoder的decode方法的第二参数是可以用标准字符集类的UTF-8作为参数的,这应该是现在最正规的调用方法,如下所示:

String name = req.getParameter("name"); name = URLDecoder.decode(name, StandardCharsets.UTF_8);

(标准字符集类需要JDK10以上才能解释,我的服务器的JDK版本是8,因此我这里没有采用标准字符集类的UTF-8来作为decode函数的第二参数,而是直接用的字符串“UTF-8”)

3. 修改Servlet之后问题仍然没有解决,我当时怀疑是我的Servlet逻辑有问题(解码不彻底或者什么其他毛病之类的),而tomcat的日志似乎有点问题,在我清了一次日志之后就再也不写日志了,该问题暂时没有解决。于是我决定在Java层面人工加入日志来进行debug

在Servlet中加入日志添加功能的方法参见Jquery中文网:http://www.jquerycn.cn/a_18338

标准Logger的使用可以参见该篇博客:https://blog.csdn.net/gruhgd/article/details/84026217

这里我采用的是创建一个LogUtil工具类,在其中实现如下静态方法:

public static void print(String message) { PrintWriter out = null; try { out = new PrintWriter(new FileOutputStream("/root/log.txt", true)); out.println(message); out.close(); } catch (FileNotFoundException e){ e.printStackTrace(); } }

然后对获取参数name的代码加入了一些日志来方便debug(注:事实上如果会用的话,这里的debug也可以用Intellij Idea的远程debug来进行,会比我这样用日志去debug方便很多,但是我不太会,所以没办法了emmmmmm)

代码修改如下:

String name = req.getParameter("name"); LogUtil.print("param:" + name + "\n"); name = URLDecoder.decode(name, StandardCharsets.UTF_8); LogUtil.print("after:" + name + "\n");

更新了服务端代码之后,通过浏览器调用接口,进行了一些添加操作,然后我的日志文件里面的内容……竟然是这个样子的……????!!!

param:测试

after:测试

param:测试2

after:测试2

param:不想测了

after:不想测了

 我惊了……这什么情况……我觉得可能是浏览器自动把我输入的urlencode帮我转码了(这么想的我大概是疯了emmmmm)……

然而我直接在Java中把name写死成“%e6%b5%8b%e8%af%952”,结果从日志来看,程序还是正常运行的……

于是我费了很大力气……又跑到windows系统下用微信小程序发了几次添加请求,结果也还是一样的……

这啥情况啊……

4. 思来想去……觉得可能是MYSQL的编码格式的锅……

以下开始正文.jpg

正文全都是引用其他人的链接.png

如何解决MySQL的字符编码格式问题呢?这么一些方案吧……各大的步骤都做一遍大概就好了……

一、创建数据库时修改字符编码格式为utf8

查看数据库编码格式:

mysql> show variables like 'character_set_database';

创建数据库时指定编码格式:

mysql>create database <数据库名> character set utf8;

修改数据库编码格式:

 

mysql>alter database <数据库名> character set utf8;

 

二、创建表时修改字符串编码格式为utf8

查看表编码格式:

mysql> show create table <表名>;

创建表时指定编码格式:

 create table <表名> (BLABLABLABLABLA……) default charset = utf8;

修改表的编码格式:

mysql>alter table <表名> character set utf8;

三、修改MySQL中的charset设置

我想我遇到的问题大概跟这篇博客一样?https://www.cnblogs.com/slow/p/3222933.html

我也跑了一下这个命令……确实里面是有latin的……

MySQL中的各项charset的含义可以参照博客:https://blog.csdn.net/sun8112133/article/details/79921734

但修改charset的方法请不要学习……直接set charset这种方法亲测不可行……退出mysql再登陆刚改的就没了……

修改charset的方法请参见https://blog.csdn.net/mynamepg/article/details/81044957

(不过大概是因为我的服务器是个centos的缘故,我的服务器的my.cnf文件路径与博客中的不同……用find命令找一下会发现my.cnf就直接在etc文件夹里放着……)

四、将涉及到中文的字段的编码格式手动改成utf-8

参见百度经验https://jingyan.baidu.com/article/17bd8e527b9b5785ab2bb892.html

我的服务器没有可视化界面,因此采用的是该篇经验最后的执行SQL语句的方案

 

 

第四步执行完成后……我的……中文……编码……问题……终于……解决了……(趴)


碎碎念:

 

至于为什么折腾了快八个小时呢?

我的Java后台在Ubuntu的Idea上写……但是微信小程序开发工具和xshell、xftp都在Windows上……

所以每次修改完后台以后都要发布war包然后挂到服务器上,然后切换到windows系统上进行检验,有不对的地方再切回Ubuntu

我这一下午重启了10+次吧……电脑启动还很慢……太痛苦了!!!!!!!

简直了!!!!简直了!!!简直了!!简直了!

这个环境等我闲下来我一定整合一下……