MySQL字符集
字符集
从本质上来说,计算机只能识别二进制代码,因此,不论是计算机程序还是其处理的数据,最终都必须转换成二进制码,计算机才能认识a为了使计算机不仅能做科学计算,也能处理文字信息,人们想出了给每个文字符号编码以便于计算机识别处理的办法,这就是计算机字符集的由来。本章将详细介绍字符集的发展历程以及MySQL中字符集的使用。
1 字符集概述
简单地说字符集就是一套文字符号及其编码、比较规则的集合。20世纪60年代初期,美国标准化组织ANSI发布了第一个计算机字符集 ASCII (American Standard Code for Information丨nterchange),后来进一步变成了国际标准ISO-646。这个字符集采用7位编码,定义了包括大小写英文字母、阿拉伯数字和标点符号,以及33个控制符号等。虽然现在看来,这个美式的字符集很简单,包括的符号也很少,但直到今天它依然是计算机世界里奠基性的标准,其后制定的各种字符集基本都兼容ASCII字符集
自ASCII之后,为了处理不同的文字,各大计算机公司、各国政府、标准化组织等先后发明了几百种字符集,如大家熟悉的ISO-8859系列、GB 2312-80、GBK、BIG 5等。这些五花八门的字符集,从收录的字符到编码规则各不相同,给计算机软件开发和移植带来了很大困难。一个软件要在使用不同文字的国家或地区发布,必须进行本地化开发!基于这个原因,统一字符编码,成了 20世纪80年代计算机业的迫切需要和普遍共识。
9.2 Unicode 简述
为了统一字符编码,国际标准化组织 ISO (International Organization for Standardization)的一些成员国于1984年发起制定新的国际字符集标准,以容纳全世界各种语言文字和符号。这个标准最后叫做“Universal Multiple-Octet Coded Character Set”,简称UCS,标准编号则定为ISCM0646。ISO-10646标准采用4字节(32bit)编码,因此简称UCS4。具体编码规则是:
.将代码空间划分为组(group)、面(plane)、行(raw)和格(ceil);第1个字节代表组(group),第2个字节代表面(plane),第3个字节代表行(row),第4个字节代表格(ceil),并规定
字符编码的第32位必须为0,且每个面(plane)的最后两个码位FFFEh和FFFFh保留不用;因此,丨SO-1064共有128个群组(0〜0x7F),每个群组有256个字面(00〜OjcFF),每个字
深入戌出
面有256行(00〜OxFF),每行包括256格(0〜OxFF),共有256* 128 = 32,768个字面,每个字面有 256x256-2=65,534 个码位,合计 65,534x32,768=2,147,418,丨丨2 个码位。
【SO-10646发布以后,遭到了部分美国计算机公司的反对。1988年Xerox公司提议制定新的以16位编码的统一字符集Unicode,并联合Apple、丨BM、DEC、Sun、Microsoft、
Novell等公司成立Unicode协会(The Unicode Consortium),并成立Unicode技术委员会(Unicode Technical Committee〉,专门负责Unicode文字的搜集、整理和编码,并于1991年推出了 Unicode 1.0。
都是为了解决字符编码统一问题,ISO和Unicode协会却推出了两个不同的编码标准,这显然是不利的。后来f大家都认识到了这一点,经过双方谈判,1991年10月达成协议,ISO将Unicode编码并入ISO-10646的0组0字面,叫作基本多语言文字面(Basic Multi-丨ingualPlane.BMP),共有65,534个码位,并根椐不同用途分为若干区域。除BMP夕卜的32,767个字面又分为辅助字面(supplementary planes)和专用字面(private use p丨anes)两部分,辅助字面用以收录丨SCM0646后续搜集的各国文字,专用字面供使用者自定义收录ISO-10646未收录的文字符号。其实,大部分用户只使用BMP字面就足够了,早期的丨SO-10646-1标准也只要求实现BMP字面,这样只需要2字节来编码就足够了,Unicode也正是这么做的,这叫作ISO-10646编码的基本面形式,简称为UCS-2编码,UCS-2编码转换成UCS-4编码也很容易,只要在前面加两个取值为0的字节即可。
ISO-10646的编码空间足以容纳人类从古至今使用过的所有文字和符号,但其实许多文字符号都已经很少使用了,超过99%的在用文字符号都编入了 BMP,因此,绝大部分情况下,Unicode的双字节编码方式都能满足需求,而这种双字节编码方式比起ISO-10646的4字节原始编码来说,在节省内存和处理时间上都具有优势,这也是Unicode编码方式更流行的原
因。但如果万一要使用ISO-10646 BMP字面以外的文字怎么办呢? Unicode提出了名为UTF-16 或代理法(surrogates)的解决方案,UTF 是 CS/Unicode Transformation Format 的缩写s UTF-16的解决办法是:对BMP字面的编码保持二字节不变,对其他字面的文字按一定规则将其32位编码转换为两个16位的Unicode编码,其两个字节的取值范围分别限定为0xD800〜OxDBFF 和 OxDCOO〜OxDFFF,因此,UTF-16 共有(4x256) x (4x256) =1,048,576个码位。.
虽然UTF-16解决了 ISO-10646除BMP外第1〜15字面的编码问题,但当时的计算机和网络世界还是ASCII的天下,只能处理单字节数据流,UTF-16在离开Unicode环境后,在传输和处理中.都存在问题。于是Unicode又提出了名为UTF-8的解决方案,UTF-8按一定规则将一个ISO-10646或Unicode字元码转换成1〜4个字节的编码,其中将ASCII码(0〜0x7F)转换成单字节编码,也就是严格兼容ASCII字符集;UTF-8的2字节编码,用以转换ISO-10646标准0x0080〜0x07FF的UCS-4原始码:UTF-8的3字节编码,用以转换ISO-10646标准0x0800〜OxFFFF的UCS-4原始码:UTF-8的4字节编码,用以转换丨SO-10646标准0x00010000〜0001FFFF 的 UCS-4 原始码。
上述各种编码方式,看起来有点让人迷惑。其实,ISO-10646只是给每一个文字符号分配了一个4字节无符号整数编号(UCS-4),并未规定在计算机中如何去表示这个无符号整数编号。UTF-16和UTF-8就是其两种变通表示方式。
ISCM0646与Unicode统一以后,两个组织虽然都继续发布各自的标准,但二者之间是—致的。由于Unicode最早投入应用,其编码方式更加普及,因此,许多人都知道Unicode,
但对ISO-10646却了解不多。但由于二者是一致的,因此,区分ISO-10646和Unicode的意义也就不大了。现在,大家说Unicode和ISO-10646, —般指的是同一个东西,只是Unicode
更直接、更普及罢了。二者不同版本的对应关系如下。
Unicode 2.0 等同于 ISO/丨EC 10646-1:1993。
Unicode 3.0 等同于 ISO/IEC 10646- 1:2Q00。
» Unicode 4.0 等同于 ISO/IEC 10646:2003。
最后要说的是,UTF-16和UTF-32因字节序的不同,又有了 UTF-16BE(BigEndian)、UTF-16LE (Little Endian)和 UTF-32BE (Big Endian)、UTF-32LE (Little Endian)等,在此
不做进一步介绍。
3 汉字及一些常见字符集
在计算机发展的不同阶段,我国也参照当时的国际标准和实际需要,制定了一些汉字字符集编码标准,主要内容如下所示。
® GB 2312-80:全称《信息交换用汉字编码字符集基本集》,于1980年发布。根据1SO/IEC 2022提供的字符编码扩充规范,形成双字节编码的字符集。收录了 6,763个常用汉字和682个非汉字图形符号。
^ GB 13000:全称《信息技术通用多八位编码字符集(UCS)第一部分:体系结构与基本多文种平面》,于1993年发布3根据丨SO/IEC 10646-1:1993,在CJK (中、曰、韩简称)统一汉字区和CJK统一汉字扩充区A,除收录GB 2312-80外,还收录了第1、3、5、7辅助集的全部汉字,共27,484个,以及一些偏旁部首等〇但013 13000推出后,几乎没有得到业界的支持,也就成了一个形式上的标准。
^ GBK:全称《汉字内码扩展规范》1.0版,发布于1995年。GBK在GB2312内码系统的基础上进行了扩充,收录了 GB 13000.1-1993的全部20902个CJK统一汉字,包括GB 2312的全部6,763个汉字。此外,它增补编码了 52个汉字,13个汉字结构符(在ISO/IEC 10646.1: 2000中称为表意文字描述符)和一些常用部首与汉字部件。
在GBK的内码系统中,GB 2312汉字所在码位保持不便,这样,保证了 GBK对GB 2312的完全兼容。同时,GBK内码与GB 13000.1代码 对应,为GBK向GB 13000,1
的转换提供了解决办法。有意思的是GBK并不是一个强制性的国家标准,只是一个行业指导规范,并没有强制力,但由于得到了 Microsoft Windows 95的支持而大为流行。
^ GB 18030:全称《信息技术信息交换用汉字编码字符集、基本集的扩充》,发布于2000 年3 根据丨SO/1EC 10646-1:2000,收录了 1SO/IEC 10646.1: 2000 全部 27,484个CJK统一汉字,13个表意文字描述符、部分汉字部首和部件、欧元符号等。GB 18030采用2字节或4字节编码,其二字节编码部分与GBK保持一致,因此,GB 18030是GBK的超集,也完全与GB 13000向上兼容,制定GB 18030也是为了解决GBK强制力不够的问题。
以上简要介绍了几种汉字字符集,下面将一些常用字符集的特点归纳如表9-1所示。
表9-1常用字符集比较
字符集 |
是否定长 |
编码方式 |
其他说明 |
ACSII |
是 |
单字节7位编码 |
最早的奠基字符 |
TSO-8859-l/latinl |
是 |
单字节8位编码 |
西欧字符集.经常被一些程序员用来转码 |
GB 2312-80 |
是 |
双字节编码 |
早期标准.不推荐再 |
GBK |
是 |
双字节编码 |
虽然不是国标,但支持的系统不少 |
GB 18030 |
否 |
2字节或4字节编码 |
开始有一些支持,但数据库支持的还少见 |
UTF-32 |
是 |
4字节编码 |
UCS4原始编码,目前很少采用 |
UCS-2 |
是 |
2字节编码 |
Windows 2000 内部用 UCS-2 |
UTF-36 |
否 |
2字节或4字节编码 |
Java 和 Windows XP/NT 等内部使用 UTF-16 |
UTF-8 |
否 |
1〜4字节编码 |
互联网和UMX/Linux广泛支持的Unicode ^ |
4 怎样选择合适的字符集
对数据库来说,字符集更加重要,因为数据库存储的数据大部分都是各种文字,字符集对数据库的存储、处理性能,以及日后系统的移植、推广都会有影响。
MySQL 5.0目前支持几十种字符集,UTF-8是MySQL 5.0支持的唯一Unicode字符集,但版本是3.0,不支持4字节的扩展部分。面对众多的字符集,我们该如何选择呢?
虽然没有一定之规,但在选择数据库字符集时,可以根据应用的需求,结合上面介绍的一些字符集的特点来权衡,主要考虑因素包括:
(1) 满足应用支持语言的需求,如果应用要处理各种各样的文字,或者将发布到使用不同语言的国家或地区,就应该选择Unicode字符集。对MySQL来说,目前就是UTF-8。
(2) 如果应用中涉及已有数据的导入,就要充分考虑数据库字符集对己有数据的兼容性》假如己有数据是GBK文字,如果选择GB 2312-80为数据库字符集,就很可能出现某些文字
无法正确导入的问题。
(3) 如果数据库只需要支持-•般中文,数据量很大,性能要求也很高,那就应该选择双字节定长编码的中文字符集,比如GBK。因为,相对于UTF-8而言,GBK比较“小”,每个汉字只占2个字节,而UTF-8汉字编码需要3个字节,这样可以减少磁盘1/0、数据库cache,以及网络传输的时间,从而提高性能。相反,如果应用主要处理英文字符,仅有少量汉字数据,那么选择UTF-8更好,因为GBK、UCS-2、UTF-I6的西文字符编码都是2个字节,会造成很大不必要的开销。
(4) 如果数据库需要做大量的字符运算,如比较、排序等,选择定长字符集可能更好,因为定长字符集的处理速度要比变长字符集的处理速度快。
(5) 如果所有客户端程序都支持相同的字符集,应该优先选择该字符集作为数据库字符集。这样可以避免因字符集转换带来的性能开销和数据损失.
5 MySQL支持的字符集简介
MySQL服务器可以支持多神字符集,在同一台服务器、同一个数据库甚至同一个表的不同字段都可以指定使用不同的字符集,相比Oracle等其他数据库管理系统,在同一个数据库只能使用相同的字符集,MySQL明显存在更大的灵活性。
査看所有可用的字符集的命令是show character set:
或者査看informati〇n_schemaxharacter_set,可以显示所有的字符集和该字符集默认的校对规则。
对规则。
MySQL的字符集包括字符集(CHARACTER)和校对规则(COLLATION)两个概念.
字符集是用来定义MySQL存储字符串的方式,校对规则则是定义了比较字符串的方式。字
符集和校对规则是一对多的关系,MySQL支持30多种字符集的70多种校对规则》
每个字符集至少对应一个校对规则^可以用“SHOW COLLATION LIKE •***';”命令或
者査看information_schema.COLLATIONS。査看相关字符集的校对规则。校对规则命名约定:它们以其相关的字符集名开始,通常包括一个语言名,并且以(大小写不敏感)、_cs (大小写敏感)或_bin (二元,即比较是基F字符编码的值而与language无关)结束。
例如,上面例子中GBK的校对规则,其中gbk_ChineSe_Ci是默认的校对规则,大小写不敏感的,gbk_bin按照编码的值进行比较,是大小写敏感的,
K面的这个例子中,如果指定_A’和_a'按照gbk_ChineSe_d校对规则进行比较,则认为两个字符是相同的,如果按照gbk_bin校对规则进行比较,则认^两个字符是不同的。我们事先需要确
认应用的需求,是需要按照什么样的排序方式,是否需要区分大小写,以确定校对规则的选择.
6 MySQL字符集的设置
MySQL的字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和字段级,它们分别在不同的地方设置,作用也不相同。
6.1服务器字符集和校对规则
服务器字符集和校对,在MySQL服务启动的时候确定
可以在my.cnf中设置:
[mysqld]
default-character-set=gbk
或者在启动选项中指定:
mysqld --default-character-set-gbk
或者在编译的时候指定:
./configure --with-charset=gbk
如果没有特别的指定服务器字符集,默认使用丨atinl作为服务器字符集。上面3种设置的方式都只指定了字符集,没有指定校对规则,这样是使用该字符集默认的校对规则,如果要使用该字符集的非默认校对规则,则需要在指定字符集的N时指定校对规则。
司以用“show variables like 'character_set_server’;”命令査询当前服务器的字符集和校对
mysql> show variables like 'character_set_server';
+ * + +
I Variable_name | Value |
+ — + +
I character_set_server 卜 gbk |
1 row in set (0.00 sec)
mysql> show variables like 1collation_server1;
+ +- +
I Variable_name | Value |
+ + +
I collation_server 1 gbk_chinese_ci |
+ + +
1 row in set (0.00 sec)
6.2数据库字符集和校对规则。
数据库的字符集和校对规则在创建数据库的时候指定,也可以在创建完数据库后通过“alter database”命令进行修改。需要注意的是,如果数据库里已经存在数据,因为修改字符集并不能将已有的数据按照新的字符集进行存放,所以不能通过修改数据库的字符集直接修改数据的内容,在9.7小节中通过一个具体的例子介绍了字符集的修改方法。
设置数据库字符集的规则是:
9 如果指定了字符集和校对规则,则使用指定的字符集和校对规则;
« 如果指定了字符集没有指定校对规则,则使用指定字符集的默认校对规则;
^ 如果没有指定字符集和校对规则,则使用服务器字符集和校对规则作为数据库的字
符集和校对规则^
推荐在创建数据库的时候明确指定字符集和校对规则,避免受到默认值的影响。
要显示当前数据库的字符集和校对规则,可以使用“show variables like’ character_set_
database •”和 “showvariables like* collation_database_” 命令査看:9.6.3表字符集和校对规则
表的字符集和校对规则在创建表的时候指定,可以通过alter table命令进行修改,同样,
如果表中已有记录,修改字符集对原有的记录并没有影响f不会按照新的字符集进行存放。
表的字段仍然使用原来的字符集。
设置表的字符集的规则和上面基本类似:
如果指定了字符集和校对规则,使用指定的字符集和校对规则;
9 如果指定了字符集没有指定校对规则,使用指定字符集的默认校对规则;
^ 如果没有指定字符集和校对规则,使用數据库字符集和校对规则作为表的字符集和
校对规则。
推荐在创建表的时候明确指定字符集和校对规则,避免受到默认值的影响。要显示表的
字符集和校对规则,可以使用show create table命令査看:
9.6.4列字符集和校对规则
MySQL可以定义列级别的字符集和校对规则,主要是针对相同的表不同字段需要使用
不同的字符集的情况,应该说一般遇到这种情况的几率比较小,这只是MySQL提供给我们
一个灵活设置的手段。
列字符集和校对规则的定义可以在创建表时指定,或者在修改表时调整,如果在创建表
的时候没有特别指定字符集和校对规则,则默认使用表的字符集和校对规则。
9.6.5连接字符集和校对规则
上面4种设置方式,确定的是数据保存的字符集和校对规则,对于实际的应用访问来说,还存在客户端和服务器之间交互的字符集和校对规则的设置。
对于客户端和服务器的交互操作,My丨SQL提供了 3个不同的参数:characteiLsetjlieiit、character_set_connection和charaeter_set_results,分别代表客户端、连接和返回结果的字符集,通常情况下,这3个字符集应该是相同的,才可以确保用户写入的数据可以正确地读出,特别是对于中文字符,不同的写入字符集和返回结果字符集将导致写入的记录不能正确读出。
通常情况下,不会单个地设置这3个参数,可以通过以下命令:
SET NAMES ***;
来设置连接的字符集和校对规则,这个命令可以同时修改这3个参数的值。使用这个方法修改连接的字符集和校对规则,需要应用每次连接数据库后都执行这个命令。
另外一个更简便的办法,是在my.cnf中设置以下语句:
[mysql]
default-character-set=gbk
这样服务器启动后,所有连接默认就是使用GBK字符集进行连接的,而不需要在程序中再执行set names命令。
另外,字符串常量的字符集也是由character_set_connection参数来指定的。
可以通过“Lcharset nameystring' [COLLATE collation name]”命令强制字符串的字符集和校对规则。例如:
select,gbk 1字符集丨;
select 1 字符集’;
通常情况下,基本不需要用户强制指定字符串字符集。
9.7 字符集的修改步驟
如果在应用开始阶段没有正确的设置字符集,在运行一段时间以后才发现存在不能满足
要求需要调整,又不想丢弃这段时间的数据,那么就需要进行字符集的修改。字符集的修改
不能直接通过 “alter database character set ***” 或者 “alter table tablename character set ***”
命令进行,这两个命令都没有更新已有记录的字符集,而只是对新创建的表或者记录生效。
已有记录的字符集调整,需要先将数据导出,经过适当的调整重新导入后才可完成。
以下模拟的是将latinl字符集的数据库修改成GBK字符集的数据库的过程。
导出表结构:
mysqldump -uroot -p --default-character-set=gbk -d databasename>createtab.sql
其中-default-character-set=gbk表示设置以什么字符集连接,-d表示只导出表结构,不导
出数据。
手工修改createtab.sql中表结构定义中的字符集为新的字符集。
确保记录不再更新,导出所有记录。
mysqldump -uroot 一p --quick ——no-create-info --extended-insert --default-char ac ter- set-lat ini databasename> data.sql
v* -quick:该选项用于转储大的表。它强制mysqldump从m务器一次一行地检索表中的行而不是检索所有行,并在输出前将它缓存到内存中。
9 -extended-insert:使用包括几个VALUES列表的多行INSERT语法。这样使转储文件更小,重栽文件时可以加速插入。
-no-create^info:不写重新创建每个转储表的CREATE TABLE语句。
--de&uk-character-set=latinl:按照原有的字符集导出所有数据,这样导出的文件中,所有中文都是可见的,不会保存成孔码。
(4)打开 data.sql,将 SET NAMES latinl 修改成 SETNAMES gbk。
(5>使用新的字符集创建新的数据库。
create database databasename default charset gbk;
创建表,执行 createtab.sql。
mysql -uroot -p databasename < createtab•sql
导入数据,执行data.sql。
mysql -uroot -p databasename < data.sql
注意:选择目标字符集的时候,要注意最好是源字符集的超级,或者确定比源字符集的字库更大,否则如果目标字符集的字库小于源字符集的字库,那么目标字符集中不支持的字符倒入后会变成乱码,丢失一部分数据。例如,GBK字符集的字库大于GB 2312字符集,那么GBIC字符集的数据,如果导入GB2312数据库中,就会丟失GB 2312中不支持的那部分汉字的数据。
小结
基本概念
• 字符(Character)是指人类语言中最小的表义符号。例如’A'、’B'等;
• 给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给字符’A'赋
予数值0,给字符’B'赋予数值1,则0就是字符’A'的编码;
• 给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就是字符集(Character Set)。例如,给定字符列表为
{’A',’B'}时,{’A'=>0, ‘B’=>1}就是一个字符集;
• 字符序(Collation)是指在同一字符集内字符之间的比较规则;
• 确定字符序后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;
• 每个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);
• MySQL中的字符序名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感)、_cs(表示大小写敏感)或_bin(表示按
编码值比较)结尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等价的;
MySQL字符集设置
• 系统变量:
– character_set_server:默认的内部操作字符集
– character_set_client:客户端来源数据使用的字符集
– character_set_connection:连接层字符集
– character_set_results:查询结果字符集
– character_set_database:当前选中数据库的默认字符集
– character_set_system:系统元数据(字段名等)字符集
– 还有以collation_开头的同上面对应的变量,用来描述字符序。
• 用introducer指定文本字符串的字符集:
– 格式为:[_charset] ’string’ [COLLATE collation]
– 例如:
SELECT _latin1 ’string’;
SELECT _utf8 ‘你好’ COLLATE utf8_general_ci;
– 由introducer修饰的文本字符串在请求过程中不经过多余的转码,直接转换为内部字符集处理。
MySQL中的字符集转换过程
1. MySQL Server收到请求时将请求数据从character_set_client转换为character_set_connection;
2. 进行内部操作前将请求数据从character_set_connection转换为内部操作字符集,其确定方法如下:
- 使用每个数据字段的CHARACTER SET设定值;
- 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);
- 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;
- 若上述值不存在,则使用character_set_server设定值。
3. 将操作结果从内部操作字符集转换为character_set_results。
我们现在回过头来分析下我们产生的乱码问题:
a 我们的字段没有设置字符集,因此使用表的数据集
b 我们的表没有指定字符集,默认使用数据库存的字符集
c 我们的数据库在创建的时候没有指定字符集,因此使用character_set_server设定值
d 我们没有特意去修改character_set_server的指定字符集,因此使用mysql默认
e mysql默认的字符集是latin1,因此,我们使用了latin1字符集,而我们character_set_connection的字符集是UTF-8,插入中
文乱码也再所难免了。
常见问题解析
• FAQ-1 向默认字符集为utf8的数据表插入utf8编码的数据前没有设置连接字符集,查询时设置连接字符集为utf8
– 插入时根据MySQL服务器的默认设置,character_set_client、character_set_connection和character_set_results均为latin1;
– 插入操作的数据将经过latin1=>latin1=>utf8的字符集转换过程,这一过程中每个插入的汉字都会从原始的3个字节变成6个字节保
存;
– 查询时的结果将经过utf8=>utf8的字符集转换过程,将保存的6个字节原封不动返回,产生乱码。参考下图:
• 向默认字符集为latin1的数据表插入utf8编码的数据前设置了连接字符集为utf8(我们遇到的错误就是属于这一种)
– 插入时根据连接字符集设置,character_set_client、character_set_connection和character_set_results均为utf8;
--插入数据将经过utf8=>utf8=>latin1的字符集转换,若原始数据中含有\u0000~\u00ff范围以外的Unicode字符,会因为无法在
latin1字符集中表示而被转换为“?”(0×3F)符号,以后查询时不管连接字符集设置如何都无法恢复其内容了。转换过程如下图:
检测字符集问题的一些手段
• SHOW CHARACTER SET;
• SHOW COLLATION;
• SHOW VARIABLES LIKE ‘character%’;
• SHOW VARIABLES LIKE ‘collation%’;
• SQL函数HEX、LENGTH、CHAR_LENGTH
• SQL函数CHARSET、COLLATION
使用MySQL字符集时的建议
• 建立数据库/表和进行数据库操作时尽量显式指出使用的字符集,而不是依赖于MySQL的默认设置,否则MySQL升级时可能带来很大困
扰;
• 数据库和连接字符集都使用latin1时,虽然大部分情况下都可以解决乱码问题,但缺点是无法以字符为单位来进行SQL操作,一般情
况下将数据库和连接字符集都置为utf8是较好的选择;
• 使用mysql CAPI(mysql提供C语言操作的API)时,初始化数据库句柄后马上用mysql_options设定MYSQL_SET_CHARSET_NAME属性为
utf8,这样就不用显式地用SET NAMES语句指定连接字符集,且用mysql_ping重连断开的长连接时也会把连接字符集重置为utf8;
• 对于mysql PHP API,一般页面级的PHP程序总运行时间较短,在连接到数据库以后显式用SET NAMES语句设置一次连接字符集即可;
但当使用长连接时,请注意保持连接通畅并在断开重连后用SET NAMES语句显式重置连接字符集。
其他注意事项
• my.cnf中的default_character_set设置只影响mysql命令连接服务器时的连接字符集,不会对使用libmysqlclient库的应用程序产生
任何作用!
• 对字段进行的SQL函数操作通常都是以内部操作字符集进行的,不受连接字符集设置的影响。
• SQL语句中的裸字符串会受到连接字符集或introducer设置的影响,对于比较之类的操作可能产生完全不同的结果,需要小心!
总结
根据上面的分析和建议,我们解决我们遇到问题应该使用什么方法大家心里应该比较清楚了。对,就是在创建database的时候指定字符
集,不要去通过修改默认配置来达到目的,当然你也可以采用指定表的字符集的形式,但很容易出现遗漏,特别是在很多人都参与设计的时
候,更容易纰漏。
虽然不提倡通过修改mysql的默认字符集来解决,但对于如何去修改默认字符集,我这里还是给出一些方法,仅供大家参考。
MySQL默认字符集
MySQL对于字符集的指定可以细化到一个数据库,一张表,一列.传统的程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的
是默认的配置.
(1)编译MySQL 时,指定了一个默认的字符集,这个字符集是 latin1;
(2)安装MySQL 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的;
(3)启动mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的配置,此时
character_set_server 被设定为这个默认的字符集;
(4)安装 MySQL选择多语言支持,安装程序会自动在配置文件中把default_character_set 设置为 UTF-8,保证缺省情况下所有的数据
库所有表的所有列的都用 UTF-8 存储。
查看默认字符集
(默认情况下,mysql的字符集是latin1(ISO_8859_1),如何查看在上面我们已经给出了相关命令
修改默认字符集
(1) 最简单的修改方法,就是修改mysql的my.ini文件中的字符集键值,
如 default-character-set = utf8
character_set_server = utf8
修改完后,重启mysql的服务
(2) 还有一种修改字符集的方法,就是使用mysql的命令
mysql> SET character_set_client = utf8 ;
mysql> SET character_set_connection = utf8 ;
mysql> SET character_set_database = utf8 ;
mysql> SET character_set_results = utf8 ;
mysql> SET character_set_server = utf8 ;
mysql> SET collation_connection = utf8 ;
mysql> SET collation_database = utf8 ;
mysql> SET collation_server = utf8 ;
设置了表的默认字符集为utf8并且通过UTF-8编码发送查询,存入数据库的仍然是乱码。那connection连接层上可能出了问题。解决方
法是在发送查询前执行一下下面这句: SET NAMES 'utf8';它相当于下面的三句指令:
SET character_set_client = utf8;
SET character_set_results = utf8;
SET character_set_connection = utf8;