热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mysqljson中文_MySQL对JSON类型UTF8编码导致中文乱码探讨

前言继上文发表之后,结合评论意见并亲自验证最终发现是编码的问题,但是对于字符编码还是有点不解,于是乎,有了本文,

前言

继上文发表之后,结合评论意见并亲自验证最终发现是编码的问题,但是对于字符编码还是有点不解,于是乎,有了本文,我们来学习字符编码,在学习的过程中,我发现对于MySQL中JSON类型的编码导致数据中文出现乱码还有可深挖之处,接下来我们来分析一下,若有错误之处,还请批评指出。

字符编码

评论中指出任何不在基本多文本平面的Unicode字符,都无法使用MySQL的utf8字符集存储,包括Emoji 表情(Emoji 是一种特殊的Unicode 编码,常见于IOS和Android 手机上)和很多不常用的汉字,以及任何新增的 Unicode 字符等等(utf8的缺点),然而啥是多文本平面,详情维基百科《https://en.wikipedia.org/wiki/Plane_(Unicode)》。首先我们了解下什么是Unicode,Unicode是通用字符集,它是一种标准,该标准在一处定义了编写在计算机上使用的大多数活动语言所需的所有字符,它的目标是成为并且在很大程度上已经是已编码的所有其他字符集的超集。在计算机或网络中的文本我们通过字符组成,字符代表字母、标点符号或其他符号。不同的组织收集了不同的字符集并为其创建了编码-一个字符集可能仅覆盖基于拉丁语的西欧语言(不包括保加利亚或希腊等欧盟国家),另一个可能覆盖特定的远东语言(例如(例如日语),其他语言可能是以特殊方式设计的,代表世界上某处其他语言的众多语言之一。但是我们并不能保证应用程序将支持所有编码,也不能保证给定的编码将满足我们代表给定语言的所有需求,另外,通常不可能在同一网页或数据库中组合不同的编码,因此使用“传统”编码方法来支持多语言页面通常非常困难,所以Unicode协会提供了一个大的,单字节字符集,旨在包括所有需要的世界上任何书写系统,包括古老的脚本(如楔形文字,哥特式和埃及的象形文字)的字符,所以统一字符编码,将其作为Web和操作系统体系结构的基础,并且得到所有主要Web浏览器和应用程序的支持。当前的Unicode字符分为17组编排,每组被称之为一个平面(Plane),所以将字符划分为0-16号的平面,而每平面拥有65536(即216)个代码点即范围区间在0x000到0xFFFF之间,而0号平面就是基本多语言平面(BMP:Basic Mutiingual Plane)。在基本多文本平面上针对每一种文字或者其补充或者其扩展都给出了一个编码范围,比如拉丁文【0000-007F】,拉丁文-补充【0080-00FF】等等。说了这么多,我们只需要记住一点即可:在Unicode字符集中前65536个代码点构成了基本多语言平面简称BMP,BMP中包含了大多常用的字符,另外Unicode字符集还包含了一百万个其他代码点的位置空间,我们称之为补充字符。我们需要区分字符集、编码字符集和编码的概念,字符集或字符串包含可能用于特定目的的字符集,它是支持计算机上的西欧语言所需的字符集,与计算机完全无关,而编码字符集是一组用于该唯一的号码被分配给每个字符的字符,有时候我们将编码字符集也可称作为代码页,编码字符集的单位称为代码点,代码点值表示字符在编码字符集中的位置。例如,Unicode编码字符集中字母á的代码点为十进制225,十六进制表示法为0xE1。而字符编码反映编码字符集被映射到用于在计算机操纵字节的方式。一个字符集可以有多种编码,许多字符编码标准,例如ISO 8859系列中定义的标准,都为给定字符使用单个字节,并且编码是对编码字符集中字符标量位置的直接映射。例如,ISO 8859-1编码字符集中的字母A在第65个字符位置(从零开始),并且使用值为65的字节进行编码并以此在计算机中表示,对于ISO 8859-1而言,这将永远不会再改变,但是,对于Unicode,事情并没有如此简单,尽管Unicode编码字符集中字母á的代码点始终为225(十进制),但在UTF-8中,它在计算机中由两个字节表示,换句话说,在此字符的编码字符集值和编码值之间不是简单的一对一映射,另外,在Unicode中,针对同一字符可以有多种编码的方式。例如,字母á可以用一种编码形式的两个字节表示,而用另一种编码形式的四个字节表示。可以与Unicode一起使用的编码形式称为UTF-8,UTF-16和UTF-32。

ccdc2caecd71d6f8b76acf66fb51b16d.png

UTF-8使用1个字节表示ASCII集中的字符,使用2个字节表示其他几个字母块中的字符,使用3个字节表示BMP的其余部分,补充字符使用4个字节。UTF-16对BMP中的任何字符使用2个字节,对补充字符使用4个字节。UTF-32对所有字符使用4个字节。基本多语言平面对应代码点存储的是常用字符,上述针对不同字符在其对应代码点,然后计算出该字符的16进制的字符串,举个栗子,将【好】字进行UTF-8编码看看该字符的字节值和字节数,如下:

var bytes = Encoding.UTF8.GetBytes("好");var hexString = BitConverter.ToString(bytes);

f9141d5c336962ac85b2c170e27bd865.png

到此我们大概了解完了字符编码,接下来我们再次回到上一节的问题,上一节将我姓名作为JSON存储到数据库中去,但是最终获取数据时,将出现乱码,因为其表编码为utf8,最终将表编码修改为utf8mb4才好使,为啥utf8就不行呢?通过上述对utf8的定义最多可以有4个字节,支持补充字符,所以MySQL根本就没有实现标准的utf8编码,换句话说只是部分实现了utf8编码,MySQL中的utf8又名为utf8mb3,也就是一个字符最多可通过3个字节表示且包含BMP字符,而不包含补充字符。所以无论是我的姓还是名虽然是3个字节,但是并非常用BMP字符导致。但是针对列类型为JSON类型,事实是对于获取中文真的会乱码吗?上文我用到的MySQL版本为5.7+,如下:

8ec673e9055c5ca6af42f177ccd228e0.png

接下来我们利用MySQL 8.0再来进行测试发现不会乱码,创建类和表配置编码如下:

0c274e9eab84aa690e4df1291eef02b1.png

public classt1

{public int id { get; set; }public string jdoc { get; set; }

}

d3ca287d0af2bcd838ba24344616235f.png

56706d94203c4024f4c9be4a6cbedd22.png

static void Main(string[] args)

{

SetDialect(Dialect.MySQL);var con = new MySqlConnection(@"Server=localhost;Database=user;Uid=root;Pwd=root;");var id = con.Insert(new t1() { jdoc = JsonConvert.SerializeObject(new { Data = "汪鹏"}) });var result = con.QueryFirstOrDefault("select * from t1 where id = @id", new{ id });

Console.ReadKey();

}

05e99e72a76c1ddd8578e36d5eed0603.png

随着移动端的兴起,有了表情的出现,所以从MySQL 5.5.3开始,引入utf8mb4字符集每个字符最多可使用4个字节,支持补充字符,对于BMP字符,utf8 [utf8mb3]和utf8mb4具有相同的存储特征:相同的代码值,相同的编码,相同的长度,对于补充字符,utf8 [utf8mb3]根本无法存储该字符,而utf8mb4需要4个字节来存储它,由于utf8 [utf8mb3]根本无法存储字符,因此在utf8 [utf8mb3]列中没有任何补充字符。接下来我们在针对JSON类型配置为utf8编码的情况下,我们来插入表情,此时会发现也是可以的。我们是可以获取对应字符的字节数,比如如下哭笑不得的表情为4个字节:

var emotion = Encoding.UTF8.GetByteCount("😂");

b38a815613a05c4a63947e1af43cd884.png

d79cc2a28eaf7c5fb2da62340064cd55.png

其实针对JSON类型获取数据乱码的情况早就有人提出过相关bug,详见地址《https://bugs.mysql.com/bug.php?id=81677》,不过官方一直没有任何回复,至少通过上述测试出来的结果对于utf8存储表情也可以,到底具体情况咋回事,我们还是看看8.0版本以对utf8编码描述为准,详情请见《https://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html》,对于utf8编码的描述依然还是最多可存储3个字节,如下:

37da3f4daef757da665c03a3b196357b.png

别忘记,还有注意:utf8[utf8mb3]字符集已被弃用,并会在将来的MySQL版本中移除,请改用utf8mb4,尽管utf8当前是utf8mb3的别名,但在某些时候utf8将成为对utf8mb4的引用,为避免对utf8的含义含糊不清,请考虑为字符集引用显式指定utf8mb4而不是utf8。所以到此我们已明了,针对8.0版本中的utf8编码虽说最多可支持3个字节,但是,会将utf8成为utf8mb4的引用,如此就不难理解为何上述将表配置为utf8编码时,对于JSON类型的不在常用BMP字符进行数据存储和表情皆没问题。

总结

通过此文对utf8编码的JSON类型的数据出现中文乱码的问题的学习才算告一段落, 原来版本问题使得utf8存在对utf8mb4编码的引用,知其然,知其所以然,嗯,大概是这么个道理。发表博客的好处就在这里,没有批评和指正,哪来的更进一步呢。



推荐阅读
  • Beetl是一款先进的Java模板引擎,以其丰富的功能、直观的语法、卓越的性能和易于维护的特点著称。它不仅适用于高响应需求的大型网站,也适合功能复杂的CMS管理系统,提供了一种全新的模板开发体验。 ... [详细]
  • 本文详细介绍了 `org.apache.tinkerpop.gremlin.structure.VertexProperty` 类中的 `key()` 方法,并提供了多个实际应用的代码示例。通过这些示例,读者可以更好地理解该方法在图数据库操作中的具体用途。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 原文地址:https:blog.csdn.netqq_35361471articledetails84715491原文地址:https:blog.cs ... [详细]
  • Maven + Spring + MyBatis + MySQL 环境搭建与实例解析
    本文详细介绍如何使用MySQL数据库进行环境搭建,包括创建数据库表并插入示例数据。随后,逐步指导如何配置Maven项目,整合Spring框架与MyBatis,实现高效的数据访问。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • JUnit下的测试和suite
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • 解决JavaScript中法语字符排序问题
    在开发一个使用JavaScript、HTML和CSS的Web应用时,遇到从SQLite数据库中提取的法语词汇排序不正确的问题,特别是带重音符号的字母未按预期排序。 ... [详细]
  • 数据类型--char一、char1.1char占用2个字节char取值范围:【0~65535】char采用unicode编码方式char类型的字面量用单引号括起来char可以存储一 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
author-avatar
天佑土土土
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有