记一次数据库乱码问题

最近在搞项目,但是在数据库初始化这一块老是会出现数据库乱码的情况出现。网上找了很多资料,对于数据库编码这一块有点理解,记录一下

问题出现

由于之前一直依赖于数据库可视化工具,例如mysql workbench,navicat之类的,这一类书数据库可视化工具一般都有默认的编码,例如mysql workbench使用的编码就是utf8mb4编码。

之前一直使用的是mysql workbench初始化sql,由于项目快要完结了,要对项目镜像容器化处理,mysql也作为容器之一(方便部署,实际不会容器化数据库)。那么必不可免的就是处理相关建库建表的操作了。对于容器化的操作而言,直接将init.sql放在/docker-entrypoint-initdb.d文件夹下就会自动执行。

但是用这种方式初始化的表,如果存在一些中文字符的话,会出出现乱码的情况发生,而使用一些可视化工具就不会出现这类问题。

问题分析

这里我们要理解一下数据库编码的问题。mysql默认编码为latin1,使用的是单字节来表示编码,作为ascii的一种拓展。而中国文化博大精深,仅仅使用单字节肯定是不够的,所以我们一般使用的是unicode编码,而utf8编码作为unicode编码的一种子集,被广泛使用于我们日常生活。

utf8最多使用3字节来表示一个中文字符,但是有些emjoy 表情包就无法存储到我们的数据库中了,于是有一种编码叫做utf8mb4(utf8 most byte 4)允许使用4个字节来存储emjoy 表情。当然了,还有一些大小写敏感,口音敏感的问题这里就不展开说了,有兴趣可以看一下这篇文章:从一个慢查询到MySQL字符集编码

使用show variables like 'char%'查看数据库的编码(mysql workbench)
在这里插入图片描述
使用show variables like 'char%'查看数据库的编码(docker 容器里面)

> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8mb3                    |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

我们这里补充一下编码的知识,数据库之所以会产生乱码就是编码和解码的方式不一致产生的。而数据库编码总的来说有三大块:客户端编码(client),数据库编码(database),还有结果输出编码(results)。

这里我们可以看到,不同的地方在于character_set_client,character_set_connection,character_set_results,其中mysql workbench 使用的是utf8mb4docker mysql使用的是latin1

也就是说,由于我的项目使用的是utf8mb4编码读取的,使用mysql workbench来初始化数据库的时候,默认使用的utf8mb4 编码初始化,由于编码和解码的方式一致,所以不管数据库采用什么方式存储数据都不会产生乱码的情况(除非长度不够产生字符截断的情况)。而使用docker mysql直接执行初始化的时候,使用的是latin1编码区入库的,而我的项目仍然是utf8mb4 编码读取,由于编码和解码的方式不一致导致乱码。

问题解决

我们在实行初始化语句的的时候使用utf8mb4编码即可解决问题。

SET character_set_client = utf8mb4;

注意,我们这里还有一个character_set_connection编码,是连接字符集。相关介绍可以看一下上面提到的文章(从一个慢查询到MySQL字符集编码)。

假设MySQL当前没有character_set_connection这个参数,SQL语句在server端通过character_set_client参数解码之后变进入内部字符集进行比较,那么例如这样子的SQL中的字符串(“ABC”)的编码也会是character_set_client的编码值:select * from order where orderid =“ABC”。那么如果开发者想让"ABC"拥有其他编码怎么办,MySQL提供了一个叫做Character Set Introducers的[8]方法,可以这么指定 select * from order where orderid = _utf8 “ABC”。后面发现每个语句都写一个Character Set Introducers来指定编码太累了,于是提供了character_set_connection参数,对于没有Character Set Introducers的字符串,都编码成character_set_connection所指定的编码。

总结

所以mysql执行语句的时候应该是这样的一个编码的过程
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值