请教字符集的问题

在linux端登录到windows端的数据库后,提示错误的时候是乱码,在linux端登录前已经执行了export NLS_LANG='SIMPLIFIED CHINESE_CHINA.ZHS16GBK'
设置的和windows端数据库的字符集相同了,为什么还是乱码?
标签: 暂无标签
原始人

写了 32 篇文章,拥有财富 297,被 1 人关注

转播转播 分享分享 分享淘帖
回复

使用道具

P4 | 发表于 2010-12-7 14:50:16
字符集要考虑三个方面的因素,“数据库端字符集、客户端字符集、操作系统字符集”,简单来说大致的流程如下:
1、用户设置客户端的字符集环境变量即NLS_LANG
2、用户执行查询语句,此时ORACLE在服务器端会根据用户设置的客户端字符集进行相应的字符集转换,然后把转化后的数据发给客户端;
3、客户端接收到来自服务器端的数据后进行展现;
上面三个步骤中后两个步骤错误配置都会导致显示出来的字符是错误的或乱码,第二步需要注意的是两个字符集必须是包含关系,也就是说在两个字符集中都有相应字符的编码,字样才能发生无损的字符转换,否则在这一步得到的字符就已经是乱码了,所以这一步关键看“服务器端的字符集(安装ORACLE是指定)和客户端的NLS_LANG配置”;

第三步需要操作系统的支持,假如说第二步ORACLE服务器端发生了正确的字符集转换,并且把数据传回到客户端,接下来显示数据就要靠客户端操作系统字符集的支持了,如果客户端操作系统根本不支持中文环境,那即使正确发生了字符集转换也是不能正常显示汉字的,这一点在LZ安装LINUX时是否选择安装中文支持有关;如果操作系统安装了中文支持就能够正常显示汉字了。

我做了一个在LINUX环境下访问LINUX数据库服务器的例子,给LZ参考。
环境配置
服务器字符集:AL32UTF8
--数据库端字符集
select * from nls_database_parameters;
PARAMETER            VALUE
-------------------- ------------------------------
NLS_LANGUAGE         AMERICAN
NLS_TERRITORY        AMERICA
NLS_CURRENCY         $
NLS_ISO_CURRENCY     AMERICA
NLS_NUMERIC_CHARACTE .,RS
NLS_CHARACTERSET    AL32UTF8
NLS_CALENDAR         GREGORIAN
NLS_DATE_FORMAT      DD-MON-RR
NLS_DATE_LANGUAGE    AMERICAN
NLS_SORT             BINARY
NLS_TIME_FORMAT      HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT   HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FOR DD-MON-RR HH.MI.SSXFF AM TZRMAT
NLS_DUAL_CURRENCY    $
NLS_COMP             BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP  FALSE
NLS_NCHAR_CHARACTERS AL16UTF16ET
NLS_RDBMS_VERSION    10.2.0.1.0

--设置客户端字符集
export NLS_LANG="SIMPLIFIED CHINESE"_CHINA.ZHS16GBK

--查看客户端字符集
col parameter for a20
col value for a30
select * from nls_session_parameters;

PARAMETER            VALUE
-------------------- ------------------------------
NLS_LANGUAGE         SIMPLIFIED CHINESE
NLS_TERRITORY        CHINA
NLS_CURRENCY         \uffff\uffff
NLS_ISO_CURRENCY     CHINA
NLS_NUMERIC_CHARACTE .,RS
NLS_CALENDAR         GREGORIAN
NLS_DATE_FORMAT      DD-MON-RR
NLS_DATE_LANGUAGE    SIMPLIFIED CHINESE
NLS_SORT             BINARY
NLS_TIME_FORMAT      HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT   HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FOR DD-MON-RR HH.MI.SSXFF AM TZRMAT
NLS_DUAL_CURRENCY    \uffff\uffff
NLS_COMP             BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP  FALSE

--插入中文
conn scott/tiger
insert into tt values(1,'快捷');
commit;
select * from tt;
回复

使用道具

P4 | 发表于 2010-12-7 16:13:39
本帖最后由 chenyu 于 2010-12-7 16:24 编辑

LINUX下访问WINDOWS数据库的测试
WINDOWS服务器端数据库字符集配置
SQL> select * from nls_database_parameters;

PARAMETER                      VALUE
------------------------------ --------------------------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               ZHS16GBK
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_RDBMS_VERSION              10.2.0.4.0

当前WINDOWS中的服务器中已经有一条数据了,是在WINDOWS的客户端输入的,使用windows客户端使用sqlplus查看
SQL> select name,dump(name) from a;

NAME                 DUMP(NAME)
-------------------- -----------------------------------------------------------
中国                 Typ=1 Len=4: 214,208,185,250

LINUX下用sqlplus客户端查看
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
把客户端的字符集环境变量设置成和操作系统的字符集一致,这里不能设置为"SIMPLIFIED CHINESE"_CHINA.ZHS16GBK,因为如果这么设置就不会发生字符集转换,但是客户端的操作系统是AL32UTF8(或者是和AL32UTF8兼容的字符集),服务器端直接把ZHS16GBK的编码发过来在AL32UTF8下显示肯定是乱码,我们要保证服务器端发过来的也是AL32UTF8编码,所以我们这里设置为AMERICAN_AMERICA.AL32UTF8,这样ORACLE就会在服务器端把数据由ZHS16GBK转换成AL32UTF8并发送到客户端,而客户端的操作系统也是AL32UTF8(或者是和AL32UTF8兼容的字符集)所以中文就能够正常显示了。
SQL> select * from a;

NAME
------------------------------------------------------------
中国

--在linux客户端插入中文
SQL> insert into a values('用户');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from a;

NAME
------------------------------------------------------------
用户
中国

然后在使用WINDOWS的客户端来显示
SQL> select name,dump(name) from a;

NAME                 DUMP(NAME)
-------------------- -----------------------------------------------------------
用户                 Typ=1 Len=4: 211,195,187,167
中国                 Typ=1 Len=4: 214,208,185,250
回复

使用道具

P4 | 发表于 2010-12-7 17:19:35
从WINDOWS服务器中EXP数据IMP到LINUX服务器中
WINDOWS数据库端字符集:ZHS16GBK,LINUX数据库端字符集:AL32UTF8
原理:EXP时发生字符集转换,IMP时不发生字符集转换;

在WINDOWS端导出数据
C:\>set NLS_LANG=AMERICAN_AMERICA.AL32UTF8

C:\>exp gpsdata/gpsdata@zjdb4 tables=(a) file=a.dmp

Export: Release 10.2.0.1.0 - Production on Tue Dec 7 16:28:00 2010

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in AL32UTF8 character set and AL16UTF16 NCHAR character set
server uses ZHS16GBK character set (possible charset conversion)  --注意这里发生字符集转换

About to export specified tables via Conventional Path ...
. . exporting table                              A          2 rows exported
Export terminated successfully without warnings.

在LINUX端导入数据
[oracle@gc1 shared]$ imp scott/tiger@PROD fromuser=gpsdata touser=scott file=a.dmp

Import: Release 10.2.0.1.0 - Production on Tue Dec 7 16:38:02 2010

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Data Mining options

Export file created by EXPORT:V10.02.01 via conventional path

Warning: the objects were exported by GPSDATA, not by you

import done in US7ASCII character set and AL16UTF16 NCHAR character set
import server uses AL32UTF8 character set (possible charset conversion) --这里没有发生字符集转换,直接以AL32UTF8导入
export client uses AL32UTF8 character set (possible charset conversion)
. importing GPSDATA's objects into SCOTT
. . importing table                            "A"          2 rows imported
Import terminated successfully without warnings.

在LINUX中查看导入的数据
这里开两个客户端,一个设置NLS_LANG,一个不设置
不设置NLS_LANG的客户端
SQL> select * from a;

NAME
--------------------
??   --显示为乱码
??

设置NLS_LANG的客户端
[oracle@gc1 ~]$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
SQL> select * from a;

NAME
--------------------
用户
中国

经过检查不设置NLS_LANG的客户端中的nls_database_parameters、nls_session_parameters和设置NLS_LANG的客户端中的nls_database_parameters、nls_session_parameters完全一致并没有任何不同,所以我感觉环境变量NLS_LANG除了能够影响当前客户端而且还有设置当前操作系统要显示的字符集的作用;
回复

使用道具

P4 | 发表于 2010-12-7 19:01:59
回复 chenyu 的帖子

chengyu大哥请问:
linux(客户端)----------->windows(服务器)
客户端发出一条请求需要经过几步字符集的转换?
客户端--------客户端的操作系统----------服务器端数据库   还需不需要经过服务器端的操作系统的字符集转换?
回复

使用道具

P4 | 发表于 2010-12-7 19:07:59
回复 chenyu 的帖子

您上面说的操作系统的字符集是服务器端的操作系统还是客户端的操作系统?还是两者都要有?
回复

使用道具

P4 | 发表于 2010-12-7 19:25:37
回复 chenyu 的帖子

传输的时候不会发生操作系统字符集的转换,只是显示的时候才会有操作系统字符集的转换是吗?还有就是我怎么查看linux系统是否支持中文呢?
回复

使用道具

P4 | 发表于 2010-12-7 21:19:53
linux(客户端)----------->windows(服务器)
客户端发出一条请求需要经过几步字符集的转换?
字符集的转换只发生一次,而且一定是在服务器端才有能力进行字符集转换

客户端--------客户端的操作系统----------服务器端数据库   还需不需要经过服务器端的操作系统的字符集转换?
正确的步骤是客户端设置字符集环境变量(和操作系统保持一致)然后发出查询请求,服务器端接收请求并做字符集转换,然后把转换后的结果发给客户端,客户端接收数据并展现;


您上面说的操作系统的字符集是服务器端的操作系统还是客户端的操作系统?还是两者都要有?
是客户端的操作系统


传输的时候不会发生操作系统字符集的转换,只是显示的时候才会有操作系统字符集的转换是吗?还有就是我怎么查看linux系统是否支持中文呢?
请记住,字符集转换智能发生在服务器端。至于怎样知道LINUX支持中文,好像在系统配置中有一个“语言”选项,选择进入后可以看见LINUX所安装的语言支持,如果有中文支持那就是支持中文了,还有一种方法是只要在LINUX系统中能够显示汉字,应该就表明安装了中文支持。
回复

使用道具

您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

意见
反馈