当前位置:首页 -> 焦点新闻

数据库乱码的原因与解决

2005/4/20 9:07:43       

“在SQL*Plus中用insert插进的都是中文的,为什么一存入服务器后,再select出的就是???”
“有的时候,服务器数据先导出,重装服务器,再导入数据,结果,发生数据查询成???”
……
这些问题,一般,是因为字符集设置不对造成的。
很久以来,字符集一直是困扰着众多Oracle爱好者的问题,笔者从事Oracle数据库管理和应用已经几年了,经常接到客户的类似上面提到的有关数据库字符集的“告急”和“求救”,在此我们就这个问题做一些分析和探讨。
首先,我们要明确什么是字符集?字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包括关系,如us7ascii就是zhs16gbk的子集,从us7ascii到zhs16gbk不会有数据解释上的问题,不会有数据丢失,Oracle对这种问题也要求从子集到超集的导出受支持,反之不行。在所有的字符集中utf8应该是最大,因为它基于unicode,双字节保存字符(也因此在存储空间上占用更多)。
其次,一旦数据库创建后,数据库的字符集是不能改变的。因此,在设计和安装之初考虑使用哪一种字符集是十分重要的。数据库字符集应该是操作系统本地字符集的一个超集。存取数据库的客户使用的字符集将决定选择哪一个超集,即数据库字符集应该是所有客户字符集的超集。
在实际应用中,和字符集问题关系最大的恐怕就是exp/imp了。在做exp/imp时,如果Client 和Server的nls_lang设置是一样的,一般就没有问题的。但是,要在两个不同字符集的系统之间导数据就经常会有这样或那样的问题,如,导出时数据库的显示正常,是中文,当导入到其他系统时,就成了乱码,这也是一类常见问题。
现在,介绍一些与字符集有关的NLS_LANG参数,
NLS_LANG格式:
NLS_LANG = language_territory.charset
有三个组成部分(语言、地域和字符集),每个成分控制了NLS子集的特性。其中:language 指定服务器消息的语言。
 territory 指定服务器的日期和数字格式。
 charset 指定字符集
例如:
AMERICAN_AMERICA.US7SCII
AMERICAN _ AMERICA. ZHS16GBK

还有一些子集可以更明确定义NLS_LANG参数:
DICT.BASE 数据字典基本   表版本                                              
DBTIMEZONE          数据库时区                                                                   
NLS_LANGUAGE         语言                                                                       
NLS_TERRITORY       地域                                                                      
NLS_CURRENCY        本地货币字符                                                                  
NLS_ISO_CURRENCY     ISO货币字符                                                                
NLS_NUMERIC_CHARACTERS  小数字符和组   分隔开
NLS_CHARACTERSET    字符集                                                                  
NLS_CALENDAR          日历系统                                                                
NLS_DATE_FORMAT    缺省的日期格式                                                                     
NLS_DATE_LANGUAGE   缺省的日期语言                                                                   
NLS_SORT        字符排序序列                                                           
NLS_TIME_FORMAT       时间格式                                                                    
NLS_TIMESTAMP_FORMAT  时间戳格式
……
通过props$动态性能视图,我们可以查看数据库的字符集信息:
$> sqlplus internal
SQL> desc props$
Name   Type    Nullable Default Comments

NAME     VARCHAR2(30)                            
VALUE$   VARCHAR2(4000) Y                        
COMMENT$ VARCHAR2(4000) Y  

SQL> set arraysize 1
SQL> col value$ format a40
SQL> select name,value$ from props$ where name=‘NLS_CHARACTERSET’;
NAME              VALUE$

NLS_CHARACTERSET        ZHS16GBK
SQL> select * from sys.props$;
                             
NAME               VALUE$                      
DICT.BASE               2                                
DBTIMEZONE            0:00                             
NLS_LANGUAGE            AMERICAN                         
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    TZH:TZM           
NLS_TIMESTAMP_TZ_FORMAT    DD-MON-   RR HH.MI.  SSXFF AM    TZH:TZM 
NLS_DUAL_CURRENCY      $                                
NLS_COMP              BINARY                           
NLS_NCHAR_CHARACTERSET  ZHS16GBK                         
NLS_RDBMS_VERSION      8.1.6.0.0                        
                                                           
NAME               VALUE$                           
GLOBAL_DB_NAME      SCPDB1                           
EXPORT_VIEWS_VERSION   8                           

22 rows selected                                           

SQL>
从结果可以看出:
NLS_LANG = AMERICAN _ AMERICA. ZHS16GBK
虽然,数据库的字符集是在create database的时候指定的,以后不允许改变,但在一个已经建立好的数据库上,我们可以通过修改SYS.PROPS$来修改主要是对应客户端的显示,与存储无关。
如:
SQL> conn / as sysdba
Connected.
SQL> SQL> select * from sys.props$                      
2  WHERE NAME=‘NLS_LANGUAGE’;                    

NAME           VALUE$
              
NLS_LANGUAGE     AMERICAN
SQL>                                               
SQL> UPDATE sys.PROPS$ SET VALUE$=‘SIMPLIFIED CHINESE’
2  WHERE NAME=‘NLS_LANGUAGE’;
1 row updated
SQL>                                               
SQL> select * from sys.props$                      
2  WHERE NAME=‘NLS_LANGUAGE’;                    
NAME           VALUE$              

NLS_LANGUAGE    SIMPLIFIED CHINESE  
SQL>                                                
通常出现问题的原因,可分为三种:
1. 服务器指定字符集与客户字符集不同,而与加载数据字符集一致。
解决方法:对于这种情况,只需要设置客户端字符集与服务器端字符集一致就可以了,具体操作如下:
* 查看当前字符集:
SQL> select * from sys.props$           
2  WHERE NAME=‘NLS_CHARACTERSET’;     
NAME           VALUE$
  
NLS_CHARACTERSET    ZHS16GBK 
SQL>                                        
可以看出,现在服务器端Oracle数据库的字符集为‘ZHS16GBK’
* 根据服务器的字符集在客户端作相应的配置或者安装Oracle的客户端软件时指定:
如果还没安装客户端,那么在安装客户端时,指定与服务器相吻合的字符集即可;如果已经安装好了客户端,并且客户端为 sql*net 2.0 以下版本,进入Windows的系统目录,编辑oracle.ini文件,用US7ASCII替换原字符集,重新启动计算机,设置生效;否则,如果,客户端为 sql*net 2.0 以上版本,在Win98 下 运 行REGEDIT,第一步选HKEY_LOCAL_MACHINE,第二步选择SOFTWARE, 第三步选择 Oracle, 第四步选择 NLS_LANG, 键 入 与服 务 器 端 相 同 的 字 符 集
(本例为:HKEY_LOCAL_MACHINE
SOFTWAREORACLENLS_LANG :AMERICAN _ AMERICA. ZHS16GBK)。
如果是UNIX客户端,则:
SQL> conn / as sysdba
Connected.
SQL> SQL> UPDATE sys.PROPS$ SET VALUE$=‘SIMPLIFIED CHINESE’
2  WHERE NAME=‘NLS_LANGUAGE’;
1 row updated
SQL> COMMIT;
Commit complete
SQL>
2. 服务器指定字符集与客户字符集相同,与加载数据字符集不一致。
解决方法:强制加载数据字符集与服务器端字符集一致。要做到这一点,可以通过重新创建数据库,并选择与原卸出数据一致的字符集,然后IMP数据,这种情况仅仅适用于空库和具有同一种字符集的数据。
解决这类问题,也可以先将数据加载到具有相同字符集的服务器上,然后用转换工具卸出为foxbase 格式或access格式数据库,再用转换工具转入到不同字符集的Oracle数据库中,这样就避免了Oracle字符集的困扰。目前数据库格式转换的工具很多,像power builder5.0以上版本提供的pipeline及Microsoft Access数据库提供的数据导入/导出功能等。
3. 服务器指定字符集与客户字符集不同,与输入数据字符集不一致。
对于这种情况,目前为止的都还没有太好的解决方法。
通过上面的了解,我们知道,导致在后期使用数据库时出现种种关于字符集的问题,多半是由于在数据库设计、安装之初没有很好地考虑到以后的需要,所以,我们完全可以通过在服务器上和客户端使用相同的字符集来避免由此类问题引出的麻烦。

煤炭网版权与免责声明:

凡本网注明"来源:煤炭网www.coal.com.cn "的所有文字、图片和音视频稿件,版权均为"煤炭网www.coal.com.cn "独家所有,任何媒体、网站或个人在转载使用时必须注明"来源:煤炭网www.coal.com.cn ",违反者本网将依法追究责任。

本网转载并注明其他来源的稿件,是本着为读者传递更多信息的目的,并不意味着本网赞同其观点或证实其内容的真实性。其他媒体、网站或个人从本网转载使用时,必须保留本网注明的稿件来源,禁止擅自篡改稿件来源,并自负版权等法律责任。违反者本网也将依法追究责任。 如本网转载稿件涉及版权等问题,请作者在两周内尽快来电或来函联系。

  • 用手机也能做煤炭生意啦!
  • 中煤远大:煤炭贸易也有了“支付宝”
  • 中煤开启煤炭出口贸易人民币结算新时代
  • 下半年煤炭市场依然严峻
市场动态

网站技术运营:北京真石数字科技股份有限公司、喀什中煤远大供应链管理有限公司、喀什煤网数字科技有限公司

总部地址:北京市丰台区总部基地航丰路中航荣丰1层

京ICP备18023690号-1      京公网安备 11010602010109号


关注中煤远大微信
跟踪最新行业资讯