关于Oracle for Linux sqlplus 的乱码问题

一:故障重现
 首先在Linux shell下面连接 Oracle数据库
$sqlplus    /nolog 
SQL>conn   /as   sysdba
SQL>startup(环境变量设置好以后,数据库会自动启动)
SQL>如果有问题这里差不多能显示出来,就是一个个的?????,如果用远程软件连接的话,就可能是一个个方块。
二:解决办法
     退出sqlplus,在Oracle家目录下查看环境变量文件
     ls -la
我的是.bash_profile
vim  .bash_profile
在下面一行加入
NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
或者
NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK 
export NLS_LANG
退出vim
 
 
三:$.   ./.bash_profile(重新加载环境变量)
再连数据库试试吧,应该没问题了,这里说的有个前提,就是装oracle的时候,选择的字符集是AMERICAN_AMERICA.ZHS16GBK
如果是别的字符集,就用类似方法试试。同样,在/etc/sysconfig/i18n里设置下兼容的语言以及字体。
select userenv('language') from dual
显示的结果是:
SIMPLIFIED CHINESE_CHINA.ZHS16GBK
 
那就把字符集改写成中文的NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
==================================
2011、7、11最新总结,最近的情况让我对上述结论有了新的看法,安装oracle数据库的经历少说有20次了,从11gR 1   32位跟64位,到11gR2  64位。装几次就会遇到不同的问题。R2 64位版本貌似对系统的要求比较高,内存资源池的共享区要求貌似不小。

总之,今天有得到个心得结论。

上面说的都不完全对,要自己试试以后才知道。这装好之后,select  userenv('language') from dual; 结果就是简体中文,一点都没错我装的时候就是选得简体中文,这样报错之后能看个明白。
可是不管我怎么变更shell下的语言,都是显示乱码,郁闷至极的时候我就把NLS_LANG=AMERICAN_AMERICA.ZHS16GBK结果好了。
我服气了,不过显示的都是英文。
英文也行啊,总比乱码好多了。
想了想原因,可能是本机的语言没装完全吧。

==========================
==========================

Oracle NLS_LANG小结

从客户那里拿到一个数据库,客户的数据库Server的字符集是JA16SJIS,使用export的Client端的NLS_LANG是US7ASCII。问过DBA,得到的结论是由于Client使用的字符集是Server字符集的子集,所以导出的dump文件应该无效,以前也看过一本《循序渐进Oracle》,从那本书的说的情况看也应该是有问题的。但是自己还是试了试,报了很多错“长度不够”,原因是我的Oracle Instance字符集是AL32UTF8,没办法重新建了个JA16SJIS数据库,Console的NLS_LANG设置为AMERICAN_AMERICA.US7ASCII,成功导入!表中的日文字符都没有问题。 

很奇怪为什么能成功导入,做了个是试验: 

创建了一个Test表,包含日文字符。 
导出两次,NLS_LANG分别是AMERICAN_AMERICA.US7ASCII和AMERICAN_AMERICA.JA16SJIS,对比两次导出的dump文件,发现只有文件头不一样,其余部分基本一致,尤其是建表和插入的数据二进制部分完全一样。NLS_LANG的设置可能不会影响dump文件的编码。通过查询Oracle网站得到这样的一句话 

In Oracle9i the Export utility always exports user data, including Unicode data, in the character set of the database. The Import utility automatically converts the data to the character set of the target database. 

也就是说,dump文件的数据的编码和源数据库的相同,不管Client的NLS_LANG如何设置。如果源数据库的字符集和目标数据库的字符集不一致,import时会自动转换。当然在不一致的情况下,源数据库的字符集一定要是目标数据库的子集。再查了下《循序渐进Oracle》,书中关于导入导出的例子使用的Oracle 8i,应该是作者偷懒把上一版的内容直接拿过来没更新。 

另外再Oracle提供的关于NLS_LANG FAQ也列出了几条对NLS_LANG误解: 

“NLS_LANG和数据库的字符集一样或许是正确的,但是经常是不对的。不要认为NLS_LANG必须和数据库的字符集一样,这经常是错的。” 《循序渐进Oracle》中说NLS_LANG一样的话可以提高性能,因为不需要字符集的转换。其实这样的转换不时发生在Server端,Client端转换完成后传递给Server端。我觉得,只要NLS_LANG是Server的字符集的子集就可以。 

“NLS_LANG的字符集设置不会更改Client端的字符集。它只是用来告诉Oracle你在Client端使用什么字符集,你不能通过设置NLS_LANG去影响Client的字符集”。而且如果Client端的字符集和NLS_LANG不兼容,会导致数据库乱码。 

“如果你不在Client端设置NLS_LANG,那么默认会使用Server的NLS_LANG设置,这是错的。如果Oracle在安装时没有设置NLS_LANG,那么NLS_LANG不会另外再设置,而是使用默认值:AMERICAN_AMERICA.US7ASCII。语言是AMERICAN,区域是AMERICA,字符集US7ASCII” 

“设置NLS_LANG的LANGUAGE 和 TERRITORY部分不会影响存储在数据库的字符。将NLS_LANG设置为JAPANESE_JAPAN.WE8MSWIN1252不会允许你存储日文。因为WE8MSWIN1252字符集不支持日文。但是设置成AMERICAN_AMERICA.JA16SJIS会允许你存储日文,假设你输入的字符是JA16SJIS,并且数据库的字符集也支持日文(如UTF8或者JA16SJIS)” 


还需要注意的是: 

SELECT USERENV ('language') FROM DUAL返回的是Session的LANGUAGE和 TERRITORY数据库的字符集。

你可能感兴趣的:(oracle)