熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

oracle中的數據庫亂碼的原因與解決

2013-11-23 19:31:12  來源: Java核心技術 

  在SQL*Plus中用insert插進的都是中文的為什麼一存入服務器後再select出的就是???
  
  有的時候服務器數據先導出重裝服務器再導入數據結果發生數據查詢成???
  
  ……
  
  這些問題一般是因為字符集設置不對造成的
  
  很久以來字符集一直是困擾著眾多Oracle愛好者的問題筆者從事Oracle數據庫管理和應用已經幾年了經常接到客戶的類似上面提到的有關數據庫字符集的告急求救在此我們就這個問題做一些分析和探討
  
  首先我們要明確什麼是字符集?字符集是一個字節數據的解釋的符號集合有大小之分有相互的包括關系如usascii就是zhsgbk的子集從usascii到zhsgbk不會有數據解釋上的問題不會有數據丟失Oracle對這種問題也要求從子集到超集的導出受支持反之不行在所有的字符集中utf應該是最大因為它基於unicode雙字節保存字符(也因此在存儲空間上占用更多)
  
  其次一旦數據庫創建後數據庫的字符集是不能改變的因此在設計和安裝之初考慮使用哪一種字符集是十分重要的數據庫字符集應該是操作系統本地字符集的一個超集存取數據庫的客戶使用的字符集將決定選擇哪一個超集即數據庫字符集應該是所有客戶字符集的超集
  
  在實際應用中和字符集問題關系最大的恐怕就是exp/imp了在做exp/imp時如果Client 和Server的nls_lang設置是一樣的一般就沒有問題的但是要在兩個不同字符集的系統之間導數據就經常會有這樣或那樣的問題導出時數據庫的顯示正常是中文當導入到其他系統時就成了亂碼這也是一類常見問題
  
  現在介紹一些與字符集有關的NLS_LANG參數
  
  NLS_LANG格式
  NLS_LANG = language_territorycharset
  
  有三個組成部分(語言地域和字符集)每個成分控制了NLS子集的特性其中language 指定服務器消息的語言
  
  territory 指定服務器的日期和數字格式
  
  charset 指定字符集
  
  例如 
  AMERICAN_AMERICAUSSCII
  
  AMERICAN _ AMERICA ZHSGBK
  
  
  還有一些子集可以更明確定義NLS_LANG參數 
  DICTBASE 數據字典基本 表版本
  
  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 VARCHAR()
  
  VALUE$ VARCHAR() Y
  
  COMMENT$ VARCHAR() Y
  
  SQL> set arraysize
  
  SQL> col value$ format a
  
  SQL> select namevalue$ from props$ where name=NLS_CHARACTERSET;
  
  NAME VALUE$
  
  NLS_CHARACTERSET ZHSGBK
  
  SQL> select * from sysprops$;
  
  NAME VALUE$
  
  DICTBASE
  
  DBTIMEZONE :
  
  NLS_LANGUAGE AMERICAN
  
  NLS_TERRITORY AMERICA
  
  NLS_CURRENCY $
  
  NLS_ISO_CURRENCY AMERICA
  
  NLS_NUMERIC_CHARACTERS
  
  NLS_CHARACTERSET ZHSGBK
  
  NLS_CALENDAR GREGORIAN
  
  NLS_DATE_FORMAT DDMONRR
  
  NLS_DATE_LANGUAGE AMERICAN
  
  NLS_SORT BINARY
  
  NLS_TIME_FORMAT HHMI SSXFF AM
  
  NLS_TIMESTAMP_FORMAT DDMONRR HHMISSXFF AM
  
  NLS_TIME_TZ_FORMAT HHMI
  
  SSXFF AM TZH:TZM
  
  NLS_TIMESTAMP_TZ_FORMAT DDMON RR HHMI SSXFF AM TZH:TZM
  
  NLS_DUAL_CURRENCY $
  
  NLS_COMP BINARY
  
  NLS_NCHAR_CHARACTERSET ZHSGBK
  
  NLS_RDBMS_VERSION
  
  NAME VALUE$
  
  GLOBAL_DB_NAME SCPDB
  
  EXPORT_VIEWS_VERSION
  
   rows selected
  
  SQL>
  
  從結果可以看出 
  NLS_LANG = AMERICAN _ AMERICA ZHSGBK
  
  雖然數據庫的字符集是在create database的時候指定的以後不允許改變但在一個已經建立好的數據庫上我們可以通過修改SYSPROPS$來修改主要是對應客戶端的顯示與存儲無關
  
  如
  
  SQL> conn / as sysdba
  
  Connected
  
  SQL> SQL> select * from sysprops$
  
   WHERE NAME=NLS_LANGUAGE;
  
  NAME VALUE$
  
  NLS_LANGUAGE AMERICAN
  
  SQL>
  
  SQL> UPDATE sysPROPS$ SET VALUE$=SIMPLIFIED CHINESE
  
   WHERE NAME=NLS_LANGUAGE;
  
   row updated
  
  SQL>
  
  SQL> select * from sysprops$
  
   WHERE NAME=NLS_LANGUAGE;
  
  NAME VALUE$
  
  NLS_LANGUAGE SIMPLIFIED CHINESE
  
  SQL>
  
  通常出現問題的原因可分為三種 
   服務器指定字符集與客戶字符集不同而與加載數據字符集一致
  
  解決方法對於這種情況只需要設置客戶端字符集與服務器端字符集一致就可以了具體操作如下
  
  * 查看當前字符集
  
  SQL> select * from sysprops$
  
   WHERE NAME=NLS_CHARACTERSET;
  
  NAME VALUE$
  
  
  NLS_CHARACTERSET ZHSGBK
  
  SQL>
  
  可以看出現在服務器端Oracle數據庫的字符集為ZHSGBK
  
  * 根據服務器的字符集在客戶端作相應的配置或者安裝Oracle的客戶端軟件時指定
  
  如果還沒安裝客戶端那麼在安裝客戶端時指定與服務器相吻合的字符集即可如果已經安裝好了客戶端並且客戶端為 sql*net 以下版本進入Windows的系統目錄編輯oracleini文件用USASCII替換原字符集重新啟動計算機設置生效否則如果客戶端為 sql*net 以上版本在Win 下 運 行REGEDIT第一步選HKEY_LOCAL_MACHINE第二步選擇SOFTWARE 第三步選擇 Oracle 第四步選擇 NLS_LANG 鍵 入 與服 務 器 端 相 同 的 字 符 集
  
  (本例為HKEY_LOCAL_MACHINE\
  
  SOFTWARE\ORACLE\NLS_LANG AMERICAN _ AMERICA ZHSGBK)
  
   如果是UNIX客戶端 
  SQL> conn / as sysdba
  
  Connected
  
  SQL> SQL> UPDATE sysPROPS$ SET VALUE$=SIMPLIFIED CHINESE
  
   WHERE NAME=NLS_LANGUAGE;
  
   row updated
  
  SQL> COMMIT;
  
  Commit complete
  
  SQL>
   服務器指定字符集與客戶字符集相同與加載數據字符集不一致
  
  解決方法強制加載數據字符集與服務器端字符集一致要做到這一點可以通過重新創建數據庫並選擇與原卸出數據一致的字符集然後IMP數據這種情況僅僅適用於空庫和具有同一種字符集的數據
  
  解決這類問題也可以先將數據加載到具有相同字符集的服務器上然後用轉換工具卸出為foxbase 格式或access格式數據庫再用轉換工具轉入到不同字符集的Oracle數據庫中這樣就避免了Oracle字符集的困擾目前數據庫格式轉換的工具很多像power builder以上版本提供的pipeline及Microsoft Access數據庫提供的數據導入/導出功能等
  
   服務器指定字符集與客戶字符集不同與輸入數據字符集不一致
  
  對於這種情況目前為止都還沒有太好的解決方法
  
  通過上面的了解我們知道導致在後期使用數據庫時出現種種關於字符集的問題多半是由於在數據庫設計安裝之初沒有很好地考慮到以後的需要所以我們完全可以通過在服務器上和客戶端使用相同的字符集來避免由此類問題引出的麻煩

From:http://tw.wingwit.com/Article/program/Java/hx/201311/27019.html
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.