[Oracle]搞懂Oracle字符集
来源:互联网 发布:cimatrone11编程视频 编辑:程序博客网 时间:2024/06/05 04:23
基本概念
- UTF-32编码:固定使用4个字节来表示一个字符,存在空间利用效率的问题。
- UTF-16编码:对相对常用的60000余个字符使用两个字节进行编码,其余的使用4字节。
- UTF- 8编码:兼容ASCII编码;拉丁文、希腊文等使用两个字节;包括汉字在内的其它常用字符使用三个字节;剩下的极少使用的字符使用四个字节。
Oracle字符集基本原理
2. 客户端操作系统字符集:即客户端操作系统以哪种字符编码存储字符。
如果是Windows,可以使用chcp命令获得代码页(code page):
根据该代码页,到微软的官方文档《National Language Support (NLS) API Reference》找到其对应的字符集。
如果是Linux,字符集在/etc/sysconfig/i18n设置:
3. 客户端NLS_LANG参数:该参数用于向Oracle指示客户端操作系统的字符集。
有了以上3个基本概念之后,我来阐述一下Oracle字符集转换的基本原则:
- 设置客户端的NLS_LANG为客户端操作系统的字符集
- 如果数据库字符集等于NLS_LANG,数据库和客户端传输字符时不作任何转换
- 如果它们俩不等,则需要在不同字符集间转换,只有客户端操作系统字符集是数据库字符集子集的基础上才能正确转换,否则会出现乱码。
几种常见情况分析
下面先看一个例子,再透过现象看本质,我们会针对这个例子进行分析。
该例子如下:
上面例子看起来很诡异,session1和2都能正常显示自己插入的字符串,又都不能正常显示对方插入的字符串。为了弄清楚,我们首先得知道数据库里对这两个字符串是怎么存储的。我们可以使用dump函数获得字符在数据库的编码:
根据AL32UTF8的编码,“中国”两字的正确编码为(都为3个字节):
中--e4,b8,ad
国--e5,9b,bd
因此session 1插入的字符串在数据库中的编码是错误的,session 2正确。这也是为什么一定要设置NLS_LANG为客户端操作系统的字符集。
但是根据上面实验我们可以知道,数据库中存储正确,并不代表客户端能正常显示;同样地,即时数据库没有正确存储,有时候客户端也能够正常显示,这又是为什么呢?别急,请听我慢慢道来:
场景1:session 1插入,session 1查询,在数据库中存储错误,但显示正确。
插入过程:
”中国“两字在客户端操作系统字符集ZHS16GBK中的编码是”d6,d0,b9,fa",由于NLS_LANG和数据库字符集相同,数据库端对客户端传过来的字符编码不进行任何转换直接存入数据库,因此数据库中存储的编码也是“d6,d0,b9,fa”,
读取过程:
数据库端读取的编码是“d6,d0,b9,fa”,由于NLS_LANG和数据库字符集相同,客户端对数据库端传过来的字符编码不进行任何转换直接显示,编码”d6,d0,b9,fa“在客户端操作系统字符集ZHS16GBK对应的汉字为“中国”。
从以上分析可知,虽然读取时正确的,但那是因为负负得正,实际上数据库中存储是错误的,因此要特别小心这种情况,在生成库中要避免。其实只要对它进行length操作就能轻易揭开它的假面具:
得出的长度居然为3!实际的长度只是2,这会带来很多麻烦。
场景2:session 1插入,session 2查询,在数据库中存储错误,显示也错误。
插入过程和场景1一样,这里就不再累述。
读取过程:
数据库端读取的编码是“d6,d0,b9,fa”,由于NLS_LANG和数据库字符集不同,客户端对数据库端传过来的字符编码进行转换,数据库端字符集AL32UTF8里编为“d6,d0,b9,fa”无法在客户端操作系统字符集ZHS16GBK里找到对应的编码,所以只好用?代替。
场景3:session 2插入,session 1查询,在数据库中存储正确,但显示错误。
插入过程:
”中国“两字在客户端操作系统字符集ZHS16GBK中的编码是”d6,d0,b9,fa",由于NLS_LANG和数据库字符集不同,Oracle会进行字符编码转换,也就是将字符集ZHS16GBK里“中国”的编码“d6,d0,b9,fa"转换为字符集"AL32UTF8"里”中国“的编码”e4,b8,ad,e5,9b,bd“。
读取过程:
数据库端读取的编码是”e4,b8,ad,e5,9b,bd“,由于NLS_LANG和数据库字符集相同,客户端对数据库端传过来的字符编码不进行任何转换直接显示,编码”e4,b8,ad,e5,9b,bd“在客户端操作系统字符集ZHS16GBK对应的汉字为“涓 浗”(原本2个字符,现在变成了3个字符,因为ZHS16GBK的汉字以2个字节编码)。
场景4:session 2插入,session 2查询,在数据库中存储正确,显示也正确。
插入过程和场景3类似。
读取过程:
数据库端读取的编码是”e4,b8,ad,e5,9b,bd“,由于NLS_LANG和数据库字符集不同,客户端对数据库端传过来的字符编码进行转换,数据库端字符集AL32UTF8里”中国“两字的编码”e4,b8,ad,e5,9b,bd“转换成客户端操作系统字符集ZHS16GBK里“中国”两字的编码“d6,d0,b9,fa",并正常显示。
这种情况虽然经过了两次转换,都确实最正确、最推荐的方式。
附录:Oracle 字符集超集和子集的对应关系可查看:http://download.oracle.com/docs/cd/B19306_01/server.102/b14225/applocaledata.htm#sthref1988
结论:NLS_LANG只和客户端操作系统的字符集相关,如果客户端操作系统的字符集和数据库字符集间无法正确转换,则应该首先改变客户端终端的字符集,而不是简单地把NLS_LANG设为和数据库字符集一样。
- 搞懂oracle字符集
- 搞懂oracle字符集
- 搞懂oracle字符集
- 搞懂oracle字符集
- 搞懂 oracle 字符集
- 搞懂Oracle字符集
- 搞懂oracle字符集
- [Oracle] 搞懂Oracle字符集
- [Oracle]搞懂Oracle字符集
- 彻底搞懂Oracle字符集
- 彻底搞懂Oracle字符集
- 彻底搞懂Oracle字符集
- Oracle字符集 彻底搞懂 字符集
- oracle 彻底搞懂Oracle字符集
- oracle字符集
- Oracle字符集
- oracle 字符集
- oracle字符集
- [Learning OpenCV入门 3]OpenCV的数据结构及core组件【未完待续】
- UIApplicationDelegate中常用的几个方法
- VPN Azure Service 配置
- 单例模式的结构
- Android牛人启航博客地址
- [Oracle]搞懂Oracle字符集
- 进入Material Design时代
- nginx location 匹配规则
- 《剑指offer》数值的整数次方
- java使用https请求
- XCode安装插件以及手误选择了「Skip Bundle」后需要重新允许「Load Bundle」的解决方法
- hibernate 笔记(1)
- ExecutorService-10个要诀和技巧
- Fiddler手机抓包环境搭建及可能问题解决