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> UPDATE sys.PROPS$ SET value$=‘SIMPLIFIED CHINESE’
   2 WHERE NAME=‘NLS_LANGUAGE’;
  1 row updated
  
  SQL> select * from sys.props$
  2 WHERE NAME=‘NLS_LANGUAGE’;
  
  NAME value$
  NLS_LANGUAGE SIMPLIFIED CHINESE
  
  通常出现问题的原因,可分为三种: 
  1. 服务器指定字符集与客户字符集不同,而与加载数据字符集一致。
  解决方法:对于这种情况,只需要设置客户端字符集与服务器端字符集一致就可以了,具体操作如下:
  * 查看当前字符集:
  SQL> select * from sys.props$
  2 WHERE NAME=‘NLS_CHARACTERSET’;

  NAME value$
  NLS_CHARACTERSET ZHS16GBK
  
  可以看出,现在服务器端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/
  
  SOFTWARE/ORACLE/NLS_LANG :AMERICAN _ AMERICA. ZHS16GBK)。
   如果是UNIX客户端,则: 
  SQL> conn / as sysdba
  Connected.
  SQL> SQL> UPDATE sys.PROPS$ SET value$=‘SIMPLIFIED CHINESE’
  2 WHERE NAME=‘NLS_LANGUAGE’;
 

  2. 服务器指定字符集与客户字符集相同,与加载数据字符集不一致。
  解决方法:强制加载数据字符集与服务器端字符集一致。要做到这一点,可以通过重新创建数据库,并选择与原卸出数据一致的字符集,然后IMP数据,这种情况仅仅适用于空库和具有同一种字符集的数据。
  解决这类问题,也可以先将数据加载到具有相同字符集的服务器上,然后用转换工具卸出为foxbase 格式或access格式数据库,再用转换工具转入到不同字符集的Oracle数据库中,这样就避免了Oracle字符集的困扰。目前数据库格式转换的工具 很多,像power builder5.0以上版本提供的pipeline及Microsoft Access数据库提供的数据导入/导出功能等。
  
  3. 服务器指定字符集与客户字符集不同,与输入数据字符集不一致。
  对于这种情况,目前为止都还没有太好的解决方法。
  通过上面的了解,我们知道,导致在后期使用数据库时出现种种关于字符集的问题,多半是由于在数据库设计、安装之初没有很好地考虑到以后的需要,所以,我们完全可以通过在服务器上和客户端使用相同的字符集来避免由此类问题引出的麻烦


怎样修改查看Oracle字符集

a.数据库服务器字符集select * from nls_database_parameters,其来源于props$,是表示数据库的字符集。

b.客户端字符集环境select * from nls_instance_parameters,其来源于v$parameter,
  
表示客户端的字符集的设置,可能是参数文件,环境变量或者是注册表
  
c.会话字符集环境 select * from nls_session_parameters,其来源于v$nls_parameters,表示会话自己的设置,可能是会话的环境变量或者是alter session完成,如果会话没有特殊的设置,将与nls_instance_parameters一致。
  
客户端的字符集要求与服务器一致,才能正确显示数据库的非Ascii字符。如果多个设置存在的时候,alter session>环境变量>注册表>参数文件

实际情况

我用select * from nls_database_parameters
PARAMETER                      VALUE
------------------------------ ------------------------------
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

PARAMETER                      VALUE
------------------------------ ------------------------------
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_NCHAR_CHARACTERSET         AL16UTF16
NLS_RDBMS_VERSION              10.2.0.1.0

说明我在创建数据库时指定的字符集是ZHS16GBK,我用
update sys.props$ set value$='AL32UTF8' where name='NLS_CHARACTERSET';
修改了字符集,但插入中文时仍然有问题,这或许就如上面资料所说的通过修改SYS.PROPS$来修改主要是对应客户端的显示,与存储无关,
所以仍旧是乱码。
然后我重新创建了个数据库,指定字符集为AL32UTF8,插入中文就没问题了。
可见我们如果要在数据库中显示中文,在创建数据库时一定哟指定好所用的字符集。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值