首页 > 语言 > 关键词  > MySQL最新资讯  > 正文

MySQL乱码问题深层分析

2009-03-06 15:27 · 稿源:IT168

一、概述

公司新购了一批PC,准备把几个性能较优的PC升级为数据库服务器,替换老旧的机器。公司有套POS终端软件,后台数据存储是 MySQL 3.23 版。我准备硬件升级的同时升级数据库软件。但是升级过程中遇到闻名的 MySQL 的乱码问题。经过查找资料,加上自己的摸索和经验,终于完美地解决这个问题。

MySQL 的乱码问题(不仅仅包括中文乱码,也包括其它语言的乱码,以下称之为乱码问题)只存在于4.1及其以上版本。4.1之前的 MySQL 不支持多语言,所以它会将你给它的数据“原封不动”地保存,再“原封不动”地读出来。从字节的角度来看,数据在这一过程中不会产生任何变化,因此不会有乱码。

4.1及以后的版本开始支持多语言,这个所谓的多语言,就是在输入输出时 MySQL 会替你做编码转换。而这个转换规则就是由客户端编码和服务器端编码来决定的。

编码转换的规则就是,在输入数据时将编码由“客户端编码”转换为“服务器端编码”,输出时将数据由“服务器端编码”转换为“客户端编码”。

二、乱码产生原因

MySQL 字符编码是版本4.1引入的,支持多国语言,而且一些特性已经超过了其它大多数数据库管理系统。正因为这一特性才导致 MySQL 的乱码问题。

字符集是一套符号和编码。校对规则是在字符集内用于比较字符的一套规则。让我们使用一个假想字符集的例子来区别清楚。

假设我们有一个字母表使用了四个字母:‘A’、‘B’、‘a’、‘b’。我们为每个字母赋予一个数值:‘A’=0,‘B’= 1,‘a’= 2,‘b’= 3。字母‘A’是一个符号,数字0是‘A’的编码,这四个字母和它们的编码组合在一起是一个字符集。

假设我们希望比较两个字符串的值(在if……else语句中我们经常做值的比较):‘A’和‘B’。比较的最简单的方法是查找编码:‘A’为0,‘B’为1。因为0 小于1,我们可以说‘A’小于‘B’。我们做的仅仅是在我们的字符集上应用了一个校对规则。校对规则是一套规则(在这种情况下仅仅是一套规则):“对编码进行比较。”我们称这种全部可能的规则中的最简单的校对规则为一个binary(二元)校对规则。

但是,如果我们希望小写字母和大写字母是等价的,应该怎样?那么,我们将至少有两个规则:(1)把小写字母‘a’和‘b’视为与‘A’和‘B’等价;(2)然后比较编码。我们称这是一个大小写不敏感的校对规则。比二元校对规则复杂一些。

在实际生活中,大多数字符集有许多字符:不仅仅是‘A’和‘B’,而是整个字母表,有时候有许多种字母表,或者一个东方的(比如中文、日文、韩文、藏文、泰文等等)使用上千个字符的书写系统,还有许多特殊符号和标点符号。并且在实际生活中,大多数校对规则有许多个规则:不仅仅是大小写不敏感,还包括重音符不敏感(“重音符” 是附属于一个字母的符号,象德语的‘?’符号)和多字节映射(例如,作为规则‘?’=‘OE’就是两个德语校对规则的一种)。

(以上摘自MySQL 5.1 手册。更多内容可参见:https://dev.mysql.com/doc/refman/5.1/zh/charset.html)

MySQL 4.1.x开始支持以下这些事情

l 使用多种字符集(Character Set)来存储字符

l 使用多种校对规则(Collation)来比较字符串

l 在同一台服务器、同一个数据库或甚至在同一个表中使用不同字符集或校对规则来混合字符串

l 允许定义任何级别的字符集和校对规则

MySQL 4.1及以上版本的字符集支持(Character Set Support)有两个方面:字符集(Character Set)和校对规则(Collation)。 字符集和校对规则有4个级别的默认设置:服务器(server),数据库(database),数据表(table)和连接(connection)。

MySQL 中是根据下面几个变量确定服务器端和客户端用的什么字符集:

character_set_client     客户端字符集

character_set_connection   客户端与服务器端连接采用的字符集

character_set_results     SELECT查询返回数据的字符集

character_set_database    数据库采用的字符集

MySQL的字符集处理是这样的:

1、发送请求。

1)客户端发送请求到服务器端。

2)服务器端会把请求的数据从客户端字符集(character_set_client)转成服务器连接字符集(character_set_connection)。

3)然後服务器会检测存储区域(table,column)的字符集,然后把数据从连接字符集(character_set_connection)转为存储区域(table,column)的字符集,然後再存储或者查询。

2、返回请求。

1)服务器将存储区域(table,column)的字符集转换成服务器连接字符集(character_set_connection)。

2)将服务器连接字符集(character_set_connection)转换成结果字符集(character_set_results),再发送到客户端。

例如,我建立一个字符集为 gbk 的数据库(服务器端)。(MySQL 4.1 开始,在建立数据库时要指定它的字符集和校对规则,不指定就用默认的字符集和校对规则。)

连接数据库的程序(客户端)使用 gb2312 字符集(如 windows 命令行下使用 MySQL ,或者 PHP 连接MySQL ),那么在执行 insert 命令时,insert 的字符串将做一个 gb2312 到 gbk 的转换。而 select 时,数据库中保存的数据会先经过 gbk 到 gb2312 的转换之后再给你(结果集)。

好,那么为什么升级3.23(或4.0)到4.1时会乱码?举个例子说明。

例如3.23的数据库中保存的是gbk编码的数据。升级之前我将这些数据导出保存到文件里,这个文件的编码当然也是gbk的(因为3.23不支持多语言,不会对数据进行转换,也就是前面说的“原封不动地保存,原封不动地读出”)。

然后我在4.1中建立一个数据库,字符集为A;客户端字符集为B。将刚才的gbk数据导入。

1)A=gbk,B=gbk

导入数据时数据不会被转换;读出时需要set names gbk(set name命令下面将讲解)。

2)A=latin1,B=gbk

导入数据会进行gbk->latin1的转换,可能会丢失数据,产生乱码。

3)A=gbk,B=latin1

导入数据会进行latin1->gbk转换,可能会产生乱码。

4)A=latin1,B=latin1

导入数据时不会进行转换;读出时不需要set names gbk 。

大家可以看到,上面1)、4)才是正确的做法,即让A和B使用同样的字符集才不会乱码。

三、解决方案

了解了 MySQL 4.1.x 以上版本字符集处理的过程,我们就知道了怎么从原理上解决这个问题。

思路:让服务器端和客户端的字符集保持一致。

服务器端的编码是由字符集(Character Set)和校对规则(Collation)决定的。

上面提到,MySQL 中是根据下面几个变量确定服务器端和客户端用的什么字符集:

character_set_client     客户端字符集

character_set_connection   客户端与服务器端连接采用的字符集

character_set_results     SELECT查询返回数据的字符集

character_set_database    数据库采用的字符集

也就是说,只要保证这几个变量采用一致的字符集,就不会出现乱码问题了。

举报

  • 相关推荐
  • CleanMyMac上线云存储清理功能

    CleanMyMac推出全新"云存储清理"功能,支持iCloud和OneDrive两大主流云服务。该功能提供统一可视化界面,可批量删除云端和本地的重复文件,或仅解除同步保留云端文件。通过滚动列表和可视化图谱两种模式,帮助用户高效管理存储空间。所有操作均在本地完成,确保数据安全。软件提供7天免费试用,并推出Basic基础版和Plus高级版两种套餐,现有用户可免费升级体验Plus全部功能。未来计划支持腾讯云、百度云等中国本土云平台,持续优化Mac存储管理体验。

  • 轿车冲下5层楼高堤坝女子奇迹生还:坠落瞬间被甩出

    ​近日,四川巴中发生了一起令人心惊胆战的交通事故。一女子驾驶小轿车在行驶过程中突然失控,从高达约五六层楼的堤坝上猛冲而下。车辆在坠落过程中撞断了堤坝的栏杆,随后继续下坠,而女子在车辆坠落瞬间被甩出驾驶室,竟先于车辆落地。 据目击者刘先生描述,当时的情况十分危急。堤坝高度相当于五六层楼,女子坠落时恰好摔在了下方的草坪上,并被一棵小树阻

  • 女子35层坠楼奇迹生还 历经50余天救治重获新生

    ​6月10日清晨5时许,中南大学湘雅三医院上演了一场生命奇迹——一名从35楼坠落的27岁女子经多学科联合救治,成功脱离生命危险。据参与抢救的重症医学科副主任医师邢伟介绍,患者被送医时已出现颅内出血、脑挫裂伤、锁骨及骨盆多发骨折,同时伴有肝破裂、肠穿孔等严重损伤,全身多器官功能濒临衰竭。 医院立即启动绿色通道,从术前检查到进入手术室仅用不到1小时

  • 185亿元!京东拟收购德国零售商Ceconomy

    据媒体报道,京东集团宣布通过旗下德国子公司JINGDONG Holding Germany GmbH,向欧洲消费电子零售巨头CECONOMY AG所有股东发起自愿公开收购要约,拟以每股4.60欧元现金收购其全部流通股份,并建立战略合作伙伴关系。 目标公司CECONOMY估值约22亿欧元(约合人民币185亿元),旗下运营MediaMarkt和Saturn两大品牌,在欧洲12国拥有870余家门店。该公司于2017年从麦德龙集团分拆独立,是欧洲�

  • 夸克月人均打开65次 断层领先 是百度的6倍以上

    在QuestMobile 2025年AI应用市场半年报中,夸克的AI搜索插件以月人均64.9次的使用频次,遥遥领先其他AI搜索引擎。 这一数据不仅远超同类产品,更是百度AI搜索的6倍以上,展现出断层领先的用户粘性。

  • 曝iPhone屏幕将迎来大升级:苹果将首发全新双层OLED屏

    苹果制定了一项为期两年的生产计划,旨在将更先进的OLED技术应用于iPhone机型,这意味着搭载双层OLED的iPhone将在2028年后问世。 目前苹果iPad Pro已经商用双层OLED屏幕,英文名为Tandem OLED”,它在传统单层OLED的基础上额外添加一层发光层,这种设计使得原本单层OLED的发光需求能够平摊到两层OLED上,从而极大地减轻每个发光层所承受的电场强度,延缓发光材料的老化速度。 并�

  • 远超行业标准!研祥金码读码器寿命突破40000小时

    Regem Marr研祥金码智能读码器通过严格测试,产品寿命超4万小时,可持续稳定运行至少4.5年。采用铝合金多开孔支架,散热性能优异,CPU温度降低27%,机壳温度降低37%。宽温设计使工作温度范围达-25℃至55℃,适应食品冷库、高温锻造等极端环境。防护等级达IP65,高于国家标准3个防尘等级和5个防水等级,实现防水防尘。产品经过高温高湿等复杂环境测试,确保各类场景下的稳定运行能力。

  • 从构建方法论到服务加码,华为加速释放AI时代制造业数智潜能

    华为提出"三层五阶八步"数字化转型方法论,助力制造业企业应对AI时代挑战。文章指出制造业数字化转型面临技术架构创新、服务体系重构和人才技能升级三大挑战。华为通过重构"规划-建设-运营-迭代"一体化服务体系和"线下+线上"协同模式,已在汽车制造等领域实现研发效率提升30%、排产效率提升20%等显著成效。其核心在于将工业Know-how与AI技术深度融合,通过生态协同释放产业潜能。目前华为已建立覆盖全国2800个区县的服务网络,联合2500家伙伴构建智能制造解决方案。文章强调真正的智造不仅是技术突破,更要让每个产业细胞在变革中焕发新生。

  • iPhone17系列仅标准版没涨价 分析师称Pro机型将上调50美元

    苹果即将发布的iPhone17系列中,除标准版外多款机型售价或将上调。其中iPhone17Air、iPhone17Pro及iPhone17Pro Max起售价预计较前代上涨50美元,分别达到949美元、1049美元和1249美元,而iPhone17标准版将维持799美元的定价策略。

  • 一条视频狂揽240W点赞,怀旧旅行成抖音流量密码?

    ​一条模拟90年代旅行方式的视频最近在抖音火了。 7月30日,拥有近700万粉丝的抖音精选旅行作者@ahua 发布了一条记录自己徒步之旅的作品,发布24小时后,点赞量便突破100万。截至发稿前,该视频点赞量已超过240万。 在这条视频中,@ahua 选择不依靠电子地图、不携带智能手机,开展了一场与世界失联168小时、从南疆走到北疆的徒步旅程。几千米的海拔落差,让四季堆叠在列