Chinaunix首页 | 论坛 | 博客
  • 博客访问: 130748
  • 博文数量: 161
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: -30
  • 用 户 组: 普通用户
  • 注册时间: 2017-09-21 21:45
文章分类
文章存档

2009年(1)

2008年(74)

2007年(48)

2006年(38)

我的朋友

分类: Oracle

2006-07-25 09:30:52

oracle中的字符集问题经常导致客户端将部分字符显示为乱码,尤其是东亚几个国家的字符,对此需要从一下几个方面着手来解决:

通常在我们的现实环境中,存在3个字符集设置。

第一: 客户端应用字符集(Client Application Character Set)

第二: 客户端NLS_LANG参数设置

第三: 服务器端,数据库字符集(Character Set)设置

 

在服务器端创建数据库时需要设置两个字符集参数,一个是NLS_CHARACTERSET, 一个是NLS_NCHAR_CHARACTERSET,也可以在sql提示符下用select userenv(‘language’) from dual;来查询。其中前者用于存放char,varchar,varchar2等字符,后者用于存放nchar,nvarchar,nvarchar2等字符,该参数值可以通过v$nls_parameters视图查询。
一个数据库所支持的字符集可以通过以下语句来查询
    col nls_charset_id for 9999
    col nls_charset_name for a30
    col hex_id for a20
    select nls_charset_id(value) nls_charset_id,
         value nls_charset_name,
         to_char(nls_charset_id(value),'xxxx') hex_id
    from  v$nls_valid_values
    where parameter = 'CHARACTERSET'
    order by nls_charset_id(value);
如果在创建数据库时上述两个参数设置得当(特殊字符所属于的字符集是设定字符集的子集),在服务器侧的字符将不会变成乱码。
 
 
乱码多数发生客户端,原因是由于客户端的语言设置引起的,即NLS_LANG的设置,在windows环境中NLS_LANG可以通过三种方式来设置:
1. 注册表:
2.系统属性中的用户或系统环境变量
3.cmd中用set NLS_LANG=xxxx.xxxx.xxxx进行设置
三者的优先级依次为 3>2>1
查看当前oracle客户端所使用的nls_lang设置,可以在sql提示符下用 @ .[%NLS_LANG%].来查看。
在dos提示符下用echo $NLS_LANG可以查看该用户的nls_lang的设置,若返回为空值则表示没有设定。当需要修改nls_lang时,原则是:临时用set命令,个人用户用系统属性的的用户环境变量,针对所有人的修改用系统属性的系统环境变量。最后才更该注册表。
在windows中还有一个代码转换发生在oracle客户端和系统之间,这里需要用chcp来查看系统的code page代码。根据该代码页的返回值来设定nls_lang,将保证客户端显示的正常。
在unix中比较简单,在用户的.profile或.cshrc中设置NLS_LANG即可。
 
至于客户端应用字符集的问题,这有很多不同的问题,需要结合应用来具体解决,例如在forms server中虽然服务器侧的字符集和客户端设置一致,且都支持中文,但forms窗体仍然无法显示数据库中的中文数据,可能的原因就是没有安装中文字符包。
 
作后需要说明的是导入导出字符集的问题。
在导出前需要用set来设置到处的导出文件的字符集,如果该字符起是数据库字符集的超集,则导出ok,如该字符集是数据库字符集的子集,导出将失败。
在导出的dmp文件中,如该文件比较小,可以用urtrledit打开他,他的第二第三各字符组合起来表示该文件的字符集id,如 “03 54”,而0354表示什么字符集,则可以在数据库通过以下查询来确定:
elect nls_charset_name(to_number('0354','xxxx')) from dual; 返回ZHS16GBK,表示是中文字符集。其中的0354是十六进制的表示,所以要将'0354'在由字符转换成数字时要用‘xxxx’来控制,使其表示先将字符‘0354’先转化成354(十六进制),然后再转化成十进制,最后to_number('0354','xxxx')变成了数字852。
 
 
 而导入数据时的字符集问题,当进行数据导入时,主要存在以下两种情况:

1.源数据库和目标数据库具有相同字符集设置

这时,只需要设置NLS_LANG等于数据库字符集即可导入(前提是,导出使用的是和源数据库相同字符集,即三者相同)

2.源数据库和目标数据库字符集不同

如果我们导出时候使用的NLS_LANG是和源数据库相同的字符集,那么导入时就可以设置客户端NLS_LANG等于导出时使用的字符集,这

样转换只发生在数据库端,而且只发生一次。

例如:

如果进行从WE8MSWIN1252到UTF8的转换

1)使用NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252导出数据库。

这时创建的导出文件包含WE8MSWIN1252的数据

2)导入时使用NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252

这时转换仅发生在insert数据到UTF8的数据库中。

以上假设的转换只在目标数据库字符集是源数据库字符集的超集时才能转换。如果不同,一般就需要进行一些特殊的处理。

我们简单看一下导入的转换过程(以Oracle8i为例):

(1)确定导出数据库字符集环境

通过读取导出文件头,可以获得导出文件的字符集设置

(2)确定导入session的字符集,即导入Session使用的NLS_LANG环境变量

(3)IMP读取导出文件

读取导出文件字符集ID,和导入进程的NLS_LANG进行比较

(4)如果导出文件字符集和导入Session字符集相同,那么在这一步骤内就不需要转换

如果不同,就需要把数据转换为导入Session使用的字符集。

然而这种转换只能在单byte字符集之间进行。

我们看一个测试:

E:\nls2>set NLS_LANG=AMERICAN_AMERICA.US7ASCII

设置导入session NLS_LANG为US7ASCII

E:\nls2>e:\oracle\ora8i\bin\imp eygle/eygle file=Sus7ascii-Cus7ascii-exp817.dmp fromuser=eygle touser=eygle tables=test

这个导出文件是从US7ASCII数据库导出,导出客户端NLS_LANG也是US7ASCII

Import: Release 8.1.7.1.1 - Production on Fri Nov 7 00:59:22 2003

(c) Copyright 2000 Oracle Corporation. All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.7.1.1 - Production

With the Partitioning option

JServer Release 8.1.7.1.1 - Production

这时导入,在DMP文件和NLS_LANG之间不需要进行字符集转换。

Export file created by EXPORT:V08.01.07 via conventional path

import done in US7ASCII character set and ZHS16GBK NCHAR character set

import server uses ZHS16GBK character set (possible charset conversion)

export server uses UTF8 NCHAR character set (possible ncharset conversion)

. . importing table "TEST" 2 rows imported

Import terminated successfully without warnings.

(5)对于多Byte字符集的导入(如:UTF8)

需要设置导入Session字符集和导出字符集相同

否则就会遇到:IMP-16 "Required character set conversion (type %lu to %lu) not supported" 错误。

:

E:\nls2>set NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

导入Session字符集设置为ZHS16GBK

导入US7ASCII的导出文件

E:\nls2>e:\oracle\ora8i\bin\imp eygle/eygle file=Sus7ascii-Cus7ascii-exp817.dmp fromuser=eygle touser=eygle

Import: Release 8.1.7.1.1 - Production on Fri Nov 7 00:38:55 2003

(c) Copyright 2000 Oracle Corporation. All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.7.1.1 - Production

With the Partitioning option

JServer Release 8.1.7.1.1 - Production

IMP-00016: required character set conversion (type 1 to 852) not supported

IMP-00000: Import terminated unsuccessfully

在从导出文件US7ASCII到导入 NLS_LANG设置为ZHS16GBK的过程中,不支持单Byte字符集向多Byte转换,报出以上错误。

(6)导入Session字符集应该是导出字符集的超级,否则,专有的字符将难以正确转换。

(7)当数据转换为导入Session字符集设置以后,如果导入Session字符集不同于导入数据库字符集,这时还需要最后一步转换,这要求导入数据库字符

集是导入session字符集的超级,否则某些专有字符将不能正常转换。

我们继续看上面的两个过程,这里有这样两个原则:

1.如果NLS_LANG的设置和数据库相同,那么数据(在传输过程中当然是2进制码)不经过转换就直接插入数据库中。

2.如果NLS_LANG的设置和数据库不同,那么数据需要转换后才能插入数据库中。

我们再回头来看上面的第一个例子:

Export file created by EXPORT:V08.01.07 via conventional path

import done in US7ASCII character set and ZHS16GBK NCHAR character set

import server uses ZHS16GBK character set (possible charset conversion)

export server uses UTF8 NCHAR character set (possible ncharset conversion)

. . importing table "TEST" 2 rows imported

Import terminated successfully without warnings.

这时候经过第一步转换后的数据,US7ASCII到ZHS16GBK丢失首位,原样插入数据库,我们看到这时数据库中存放的就是错误的字符(在后面

部分我们做了详细的转换):

E:\nls2>sqlplus rainny/rainny

SQL*Plus: Release 9.2.0.4.0 - Production on Fri Nov 7 00:35:39 2003

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to:

Oracle8i Enterprise Edition Release 8.1.7.1.1 - Production

With the Partitioning option

JServer Release 8.1.7.1.1 - Production

SQL> select * from test;

NAME

--------------------

2bJT

test

__________________

 

附:Code Pages Supported by Windows

SBCS (Single Byte Character Set) Codepages

DBCS (Double Byte Character Set) Codepages

In these graphical representations, leadbytes are indicated by light gray background shading. Each of these leadbytes hyperlinks to a new page showing the 256 character block associated with that leadbyte. Unused leadbytes are identified by a darker gray background.

Windows OEM Code Pages

The list below provides links to graphical representations, and textual listings, of each of the Windows OEM code pages:

Windows ANSI and OEM Code Pages

The following codepages are used as both Windows ANSI and OEM codepages:

The list below provides links to graphical representations, and textual listings, of each of the ISO 8859 character sets:

 
阅读(1503) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~