Oracle字符集轉換

 

 
      這幾天在工做中碰到一個字符亂碼的問題,發如今cmd窗口的sqlplus中直接update一箇中文和使用@調用一個文件做一樣更新的時候,存儲的結果 竟不同。一時比較迷惑,對Oracle如何處理各個字符集的問題不是很清楚。特此經過一些資料和實驗總結,系統學習一下Oracle中字符集的相關知 識。

一. 字符集的基礎知識:

在網絡上已有很多網友對字符集進行了研究,我的以爲有幾個不錯的網站能夠參考
http://blog.csdn.net/tianlesoftware/article/details/4915223
http://www.itstreets.com/post/34.html
http://www.oraclefans.cn/forum/showblog.jsp?rootid=3303


二. Oracle字符集的轉換

如下用幾個實驗來學習一下Oracle對各類字符集的處理
此處涉及3個概念:數據庫服務端的字符集,客戶端的字符集和操做系統的字符集
實驗環境中:數據庫服務端的字符集是AL32UTF8

1. 客戶端和服務器端的字符集一致的時候
實驗一:客戶端字符集也是AL32UTF8, 操做系統的字符集是GB2312
CTBLAZER@106orcl>update c_language set languagename='中國' where id = 'zh-CN';

1 row updated.

CTBLAZER@106orcl>commit ;

Commit complete.

CTBLAZER@106orcl>select dump(languagename, 1016) from c_language where id = 'zh-CN';

DUMP(LANGUAGENAME,1016)
-----------------------------------------------------------------------------------------

Typ=1 Len=4 CharacterSet=AL32UTF8: d6,d0,b9,fa

CTBLAZER@106orcl>

使用dump函數以16進制查看在數據庫中的存儲,能夠看出「中國」這2個字,在數據庫中的存儲編碼是:d6,d0,b9,fa

先建一個文件t1.txt,寫上「中國」這2個字,以GB2312(codepage 爲936)的格式保存。
在cmd窗口使用type命令查看,能夠看到此時在cmd窗口能正確顯示文本。

V:\>chcp
Active code page: 936

V:\>type e:\t1.txt
中國
V:\>

再用winhex工具查看t1.txt文本,能夠看到其16進制編碼爲:D6,D0,B9,FA


實驗二:在sqlplus環境中使用@來調用一個sql文件,文件的內容是和實驗一一樣的一句sql,文件格式爲UTF8
服務器和客戶端的字符集依然是AL32UTF8, 操做系統的codepage爲936

CTBLAZER@106orcl>select dump(languagename, 1016) from c_language where id = 'zh-CN';

DUMP(LANGUAGENAME,1016)
---------------------------------------------------------------------------------------

Typ=1 Len=6 CharacterSet=AL32UTF8: e4,b8,ad,e5,9b,bd

CTBLAZER@106orcl>

一樣建一個文本文件t2.txt,以UTF8的格式保存。再使用WinHex查看, 能夠看到其16進制編碼爲:E4, B8, AD, E5, 9B, BD


經過這2個實驗,能夠清楚的看出,在客戶端和數據庫服務端的字符集一致的時候,Oracle並不進行存儲轉換。如在cmd窗口之中,
以操做系統默認的GB2312編碼的「中國」,和以文件方式按UFT8編碼格式的「中國」,都會直接存儲到Oracle服務器上。


可是咱們會發現,按UTF8格式編碼的存儲,在cmd裏面查詢的結果會是亂碼。以下:

CTBLAZER@106orcl>host chcp
Active code page: 936

CTBLAZER@106orcl>col languagename format A30
CTBLAZER@106orcl>select * from c_language where id='zh-CN';

ID                   LANGUAGENAME
-------------------- ------------------------------
zh-CN                涓浗
CTBLAZER@106orcl>

這是由於我機器cmd窗口的codepage 默認是936,而客戶端和服務器端的字符集都同樣,Oracle會不作任何轉換的把保存的字符編碼
直接返回回來,可是數據庫裏面的編碼是按UTF8的存儲的,而cmd窗口的字符編碼爲GB2312,故而是顯示的亂碼。

咱們能夠將cmd窗口的codepage先改成UTF8(codepage爲65001)格式的,則能夠看到正常的顯示「中國」這2個字了。以下:
如何修改codepage,能夠參考:http://xiangqinghu1988.blog.163.com/blog/static/58822991201222232456746/

Active code page: 65001

CTBLAZER@106orcl>select * from c_language where id = 'zh-CN';

ID                   LANGUAGENAME
-------------------- ------------------------------
zh-CN                中國

CTBLAZER@106orcl>

因 此,在Oracle沒有施行字符轉換的時候,即(客戶端和服務器端的字符集是一致的時候),若是出現亂碼,那麼則是代表客戶端的環境編碼(如cmd窗口的 編碼)和Oracle數據庫存儲的字符編碼(cmd窗口直接用sqlplus更新和調用一個UTF8文件格式的更新)不一致。若是要查看,須要修改客戶端 的環境編碼。好比修改cmd的codepage。

2. 客戶端和服務器端的字符集不一致的時候
實驗三:將客戶端的字符集設置爲ZHS16GBK,在sqlplus裏面直接更新記錄以下:

V:\>set NLS_LANG=American_America.ZHS16GBK

V:\>sqlplus ctblazer@106orcl

SQL*Plus: Release 11.2.0.1.0 Production on Thu Mar 22 15:29:43 2012

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

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

CTBLAZER@106orcl>Update c_language set languagename='中國' where id = 'zh-CN';

1 row updated.

CTBLAZER@106orcl>commit;

Commit complete.

CTBLAZER@106orcl>col languagename format A30
CTBLAZER@106orcl>select * from c_language where id = 'zh-CN';

ID                                       LANGUAGENAME
---------------------------------------- ------------------------------
zh-CN                                    中國

CTBLAZER@106orcl>select dump(languagename, 1016) from c_language where id = 'zh-CN';

DUMP(LANGUAGENAME,1016)
-----------------------------------------------------------------------------------------

Typ=1 Len=6 CharacterSet=AL32UTF8: e4,b8,ad,e5,9b,bd

CTBLAZER@106orcl>

結果頗有意思,數據庫中存儲的再也不是像實驗一中的d6,d0,b9,fa, 而是很巧的變成了UTF8格式的存儲了。若是咱們開另一個
sqlplus窗口,其客戶端字符集爲AL32UTF8,這時來查看一下這條記錄以下,發現亂碼了


V:\>sqlplus ctblazer@106orcl

SQL*Plus: Release 11.2.0.1.0 Production on Thu Mar 22 15:36:56 2012

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

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

CTBLAZER@106orcl>col languagename format A30
CTBLAZER@106orcl>select * from c_language where id = 'zh-CN';

ID                   LANGUAGENAME
-------------------- ------------------------------
zh-CN                涓浗

CTBLAZER@106orcl>

若是咱們把cmd的codepage設置爲UTF8格式的,咱們就能夠看到是正常的顯示了(這時仍是要求客戶端與服務器端的字符集一致)

Active code page: 65001
CTBLAZER@106orcl>select * from c_language where id = 'zh-CN';

ID                   LANGUAGENAME
-------------------- ------------------------------
zh-CN                中國

CTBLAZER@106orcl>

注意,這個實驗的結果比較巧合,若是將sqlplus客戶端的字符集不是設置ZHS16GBK,而是設爲其餘的字符集,那麼Oracle中存儲的就不必定是UTF8的編碼了。
實際上,若是客戶端和服務端的字符集不一致,Oracle底層會對字符編碼進行轉換,具體如何轉換我也還不清楚,望有高手深刻研究。

總的來講,在實際中若是碰到亂碼狀況,須要知曉Oracle客戶端字符集,服務器端字符集以及操做系統字符集這幾個之間的關係。1. 若是客戶端和服務器端的字符集一致,Oracle不會進行編碼轉換。直接按存儲操做系統相關的編碼格式存儲。在查詢的時候,也不會轉換,而是直接返回數據庫中存儲的編碼2. 若是客戶端和服務器端的字符集不一致,Oracle會在底層對存儲的字符進行編碼轉換。在查詢返回的時候,一樣會轉換一次。
相關文章
相關標籤/搜索