QUOTE:
最初由 sydongsun 发布
问题在于:
在客户端和服务器端都为utf-8时,假如你正确存入了汉字信息到数据库服务器上,一般来说汉字的UTF8的编码为三个byte。然后你的客户端也是 utf-8, 那么不经过转换就会通过select 显示,比如“管”的假定的信息是185,220,148 (这里是随意写的),但是你的客户端是否具有这样的字符集呢?一般的Windows操作系统是不会让你选择一种UTF8的字符集的,要么是GBK的简体中 文,要么是美国标准英文,后者是windows系统的标准英文,或者是日文操作系统等,没有一种使用UTF8的显示和输入的操作系统。
事实上,Unicode编码主要是一种信息存储的编码方式。可以支持世界上主要的语言的所有字符都能够用一个唯一的编码值在表示和存储。在信息来显示和输 入的时候,大家都还是使用各自的语言的。比如,一个网络在线商店,可以接受,中文的,泰问,日本专有字符,蒙古文的操作系统的输入的内容,同一转换成 UTF8存储到数据中,然后各个操作系统要进行读取的时候,也分别按照UTF8 到各自的操作系统编码转换进行读取。现在全世界还没有一种可以同时使用包含所有主要语言的操作系统,在Windows平台可以通过国家语言设置来进行转换 (但是要么是选择中文版,好么是选择英文版,要么是蒙古文.... ,不能同时选择所有,否则我们的键盘的键格数量要大大增加),所以,没有将客户端设 置为语言选择为UTF8的操作系统。
你需要仔细理解,我的回答并不是非常清楚。
另外,从你 select dump('管') from dual, 实际上表示的是你操作系统当前所使用的语言编码是GBT的,应为只有2个byte. 所以你的AMERICAN_AMERICA.ZHS16GBK 只能选择ZHS16GBK, 永远不要选择为UTF8, 只有你想执行数据库的字符集转换的时候,你在exp和imp的时候,为了exp数据的字符集变化,你可以临时让客户端和数据库段一致。 但是几乎很少有从utf8这种unicode转换到非unicode的工作场景的。
谢 谢你的回答,实际上怎么使用字符集这个问题我很清楚了,我只是想解释一下出现的现象而已,想通过这方面的研究加深对字符集编码的理解。事实上UFT8的两 字节编码为:110***** 10****** 第一个字节的110和第二个字节的10为标志位。三个字节的编码为:1110***** 10****** 10******,第一个字节的1110和第二、三个字节的10都是标志位,剩下的空间正好可以表示汉字。
我们再来看一下测试的数据情况:
在utf-8的环境下执行:
SQL> select dump('管',16) from dual;
ERROR:
ORA-01756: quoted string not properly terminated
管的16机制编码为:
而‘管’字的GBk编码是b9 dc ,事实上不在utf8二字节和三字节的编码范围中,它是以单字节编码的读取方式,写读b9, 然后再读dc,读到dc的时候,由utf-8的编码规则可以知道是二字节编码的,所以他会把后面的'当成二字节编码的一部分,所以就会出现'缺失的现象
SQL> select dump('管1',16) from dual;
DUMP('管1',16)
----------------------
Typ=96 Len=3: b9,dc,31
读的时候 b9 (dc,31)同样的测试可以看到:
SQL> select dump('理12',16) from dual;
DUMP('理12',16)
-------------------------
Typ=96 Len=4: c0,ed,31,32
读取的顺序 c0 (ed 31 32)
SQL> select dump('理1',16) from dual;
ERROR:
ORA-01756: quoted string not properly terminated
读取的顺序 c0 (ed 31 39),把引号吃掉了
SQL> select dump('理发',16) from dual;
DUMP('理发',16)
-------------------------
Typ=96 Len=4: c0,ed,b7,a2
读取的顺序为c0 (ed,b7, a2)
通过上面的分析就很容易知道为什么会出现引号缺省的问题了。通过这个问题的解决对字符集的理解大大加深了,谢谢各位的帮助。