时间:2021-07-01 10:21:17 帮助过:72人阅读
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);
到此我们大概了解完了字符编码,接下来我们再次回到上一节的问题,上一节将我姓名作为JSON存储到数据库中去,但是最终获取数据时,将出现乱码,因为其表编码为utf8,最终将表编码修改为utf8mb4才好使,为啥utf8就不行呢?通过上述对utf8的定义最多可以有4个字节,支持补充字符,所以MySQL根本就没有实现标准的utf8编码,换句话说只是部分实现了utf8编码,MySQL中的utf8又名为utf8mb3,也就是一个字符最多可通过3个字节表示且包含BMP字符,而不包含补充字符。所以无论是我的姓还是名虽然是3个字节,但是并非常用BMP字符导致。但是针对列类型为JSON类型,事实是对于获取中文真的会乱码吗?上文我用到的MySQL版本为5.7+,如下:
接下来我们利用MySQL 8.0再来进行测试发现不会乱码,创建类和表配置编码如下:
public class t1 { public int id { get; set; } public string jdoc { get; set; } }
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<t1>("select * from t1 where id = @id", new { id }); Console.ReadKey(); }
随着移动端的兴起,有了表情的出现,所以从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("??");
其实针对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个字节,如下:
别忘记,还有注意:utf8[utf8mb3]字符集已被弃用,并会在将来的MySQL版本中移除,请改用utf8mb4,尽管utf8当前是utf8mb3的别名,但在某些时候utf8将成为对utf8mb4的引用,为避免对utf8的含义含糊不清,请考虑为字符集引用显式指定utf8mb4而不是utf8。所以到此我们已明了,针对8.0版本中的utf8编码虽说最多可支持3个字节,但是,会将utf8成为utf8mb4的引用,如此就不难理解为何上述将表配置为utf8编码时,对于JSON类型的不在常用BMP字符进行数据存储和表情皆没问题。
通过此文对utf8编码的JSON类型的数据出现中文乱码的问题的学习才算告一段落, 原来版本问题使得utf8存在对utf8mb4编码的引用,知其然,知其所以然,嗯,大概是这么个道理。发表博客的好处就在这里,没有批评和指正,哪来的更进一步呢。
MySQL对JSON类型UTF-8编码导致中文乱码探讨
标签:覆盖 字母 乱码 man 获取 存储 系统 ref doc