1. 程式人生 > >oracle字符集和編碼

oracle字符集和編碼

一、字符集簡介

作用:可以使資料庫工具,錯誤訊息,排序次序,日期,時間,貨幣,數字,和日曆自動適應本地化語言和平臺

這裡主要說的是unicode字符集,

UTF-8、UTF-16、UCS-2是標準的Unicode字符集,即是使用UTF-8或UTF-16或UCS-2來實現編碼,UTF8指的是Oracle中的字符集,使用UTF-8來編碼

AL32UTF8、AL16UTF8是Oracle資料庫中使用基於標準Unicode字符集編碼而定義的

Oracle的字符集命名遵循以下命名規則:<Language><bitsize><encoding>   即:  <語言><位元位數><編碼> 。比如: AL32UTF8表示:AL,代表all,指使用所有語言;32,,32位;UTF8編碼。格式NLS_LANG= language_territory.charset,比如:NLS_LANG=American_America.AL32UTF8,American表示語言,影響提示資訊;America表示地區,影響伺服器的時間和數字格式;AL32UTF8字符集型別,其實三個組合第三格是最主要的,你也可以設定比如NLS_LONG=AMERICAN _ AMERICA. ZHS16GBK(ZHS16GBK表示採用GBK編碼格式、16位(兩個位元組)簡體中文字符集),

Oracle資料庫支援的Unicode字符集

Character Set     Unicode Encoding    Database Character Set    National Character Set

UTF8                   UTF-8                     Yes                                Yes(Oracle 9i and 10gonly)

AL32UTF8           UTF-8                     Yes                               No

AL16UTF16         UTF-16                   No                                Yes

二、引數設定和檢視

1、  檢視

nls_session_parameters---用於檢視會話級別的字符集

nls_instance_parameters---檢視例項級別的字符集

nls_database_parameters---檢視資料庫字符集

select userenv('language') from dual; --檢視客戶端字符集

2、  設定

一般使用NLS_LANG設定,

NLS_LANG為一個總控引數,控制了nls_language和nls_territory的行為

        該引數可以用於設定伺服器和客戶端的language和territory值,也可設定客戶端輸入資料和顯示的字符集

        只要設定了該引數,則其它引數就確定了。當然也可以只設定其中的一部分,NLS_LANG只能在環境變數中設定。

        NLS_LANG設定後,在客戶端應用程式啟動時生效。當連線到伺服器端時,客戶端使用NLS_LANG指定的資訊與

            Oracle伺服器段來通訊,該設定通常對Oracle提供的客戶端有效,如SQLPlus等

另外在linux上還有一個環境引數LANG,區別:

LANG是針對Linux系統的語言、地區、字符集的設定,對linux下的應用程式有效,如zh_CN.GB2312

NLS_LANG是針對Oracle語言、地區、字符集的設定,對oracle中的工具有效,如:SINPLIFIED CHINESE_CHINA.ZHS16GBK

四、Character Set與National Character Set 

   National Character Set:主要是用於輔助Character Set。因為早期的資料庫中很多使用了單位元組字符集,但隨著業務的需要及發展,需要使用到諸如nchar,nvarchar等Unicode字元或者需要擴充套件到世界各地儲存不同的字元,因此輔助字符集應運而生。

    兩者的比較:

       Character Set                                  NationalCharacter Set

       ----------------------                        -----------------------

       建立時被定義                                 建立時被定義

       建立見後不能被改變,僅有很少列外              可以被改變

       可以儲存列的型別為char,varchar2,clob,long      可以儲存的型別為NCHAR,NVARCHAR2,NCLOB

       能夠儲存可變長度字符集                        能夠儲存Unicode字符集,要麼使用AL16UTF8或UTF8

五、注意地方

1、資料庫字符集一旦確定,最好不要修改,否則產生意想不到的問題,最好讓客戶端的字符集匹配資料庫的

2、在不同庫之前,不同平臺間導庫的時候特別注意字符集問題,一般匯入匯出的時候會提示的

六,兩個有用的函式

一個是unistr--將包含字元和 Unicode 轉義序列的字串轉換為AL16UTF16或 UTF8字元
一個是dump--察看列在資料庫中儲存的內容

select dump(n'中',1016) from dual;
select dump(n'1',1016) from dual;

SELECT UNISTR( '\0031' )from dual;
SELECT UNISTR( '\4e2d' )from dual;
select  UNISTR('Hello中國') a1 from dual;

七,ASCII表

表二,


八,修改資料庫字符集

一般不建議修改字符集,推薦使用匯入匯出,如果是超集也可以,並且應該限制會話模式下(RESTRICTED)

shutdown immediate;

startup mount;

alter session set sql_trace=true;

alter system enable restricted session;

alter system set job_queue_processes=0;

alter system set aq_tm_processes=0;(QMNC程序對於AQ表來說就相當於CJQ0程序之於作業表,Qnnn程序對於QMNC程序就相當於Jnnn程序與CJQ0程序的關係)

alter database open;

alter database character set internal_use AL32UFT8;

shutdown immediate;

startup;

另下參考網路

字符集:人們根據需要把某些字元收集到一處,並賦以名稱,於是便有了某某字符集。

  編碼:當前面收集的工作完成以後,為了讓只認識數字的“愚蠢”的計算機也能夠儲存字元,人們不得不為集合裡的每一個字元分配”身份證號碼”,這就是編碼,從此,終於可以以儲存編碼的方式在計算機中儲存字元了。

  在字符集與編碼世界的漫漫歷史長河裡(偽),出現過若干個讓計算機工作者們如雷貫耳的名字,這些名字,有些已經成了浮雲飄散了,有些還在我們的程式碼中折騰。

  ASCII:

  ASCII字符集:包含大小寫英文、阿拉伯數字、標點,以及一些不可見的控制符共128個。

  ASCII編碼:使用7位表示一個字元。編碼範圍是[0-127](即Hex[00-7F]),其中[0-31](Hex[00-1F])部分以及127(Hex7F)是控制符,其餘的都是些可見字元。

  GB2312:

  GB2312字符集:ASCII字符集+7000左右漢字字元。

  GB2312編碼:相容ASCII編碼。對位元組進行判斷,如值<=127,則意義等同於ASCII編碼;如值>127,則它需要跟其後的另一個位元組合併表示一個字元。其理論漢字編碼空間為128X256,超過3萬個字元。

  GBK:

  GBK字符集:GB2312字符集+20000左右漢字字元。

  GBK編碼:相容GB2312編碼。利用了GB2312編碼閒置的編碼空間。

  GB18030:

  GB18030字符集:GBK字符集+若干漢字+若干少數民族字元,為目前國內最新的字符集。

  GB18030編碼:相容GBK編碼。繼續利用GBK編碼閒置的編碼空間,對於超出編碼空間的則採用4個位元組表示。

  BIG5:

  BIG5字符集:ASCII字符集+13000左右漢字(繁體)。

  BIG編碼:相容ASCII編碼。其編碼模式類似於GB2312.

  UNICODE:(UNICODE一詞在日常使用中顯得寬泛、混亂,在不同的語境中可以是以下意思之一。)

  UNICODE標準:由一些組織提出的一套標準,對人類文字的顯示、編碼等進行了一系列的規定。

  UNICODE字符集:目前最新版的UNICODE字符集中已經包含各種語言的超過10萬的字元。

  UNICODE編碼:(狹義的UNICODE編碼可能指UCS-2,也可能指UTF-16;廣義的UNICODE編碼可以指包括以下四種在內的若干種對UNICODE標準的編碼實現。)

  ①UTF-32編碼:固定使用4個位元組來表示一個字元,存在空間利用效率的問題。

  ② UTF-16編碼:對相對常用的60000餘個字元使用兩個位元組進行編碼,其餘的(即’補充字元supplementary characters’)使用4位元組。

  ③UCS-2編碼:是對UNICODE早期版本的實現,它與UTF-16的唯一區別是它不包括’補充字元’,所以它對字元的編碼只使用兩個位元組。目前此編碼模式已過時。

  ④ UTF-8編碼:相容ASCII編碼;拉丁文、希臘文等使用兩個位元組;包括漢字在內的其它常用字元使用三個位元組;剩下的極少使用的字元使用四個位元組。

  ISO8859-1:(使用Oracle的同志們可能見過這個WE8ISO89859P1,沒錯,就是它。)

  ISO8859-1字符集:ASCII字符集+若干西歐字元,例如字母Â、Ë。

  ISO8859-1編碼:使用8位表示一個字元,同時移除了原ASCII編碼中的控制符(即[0-31],及127)。

  Code page:(可以把”code page”認為是”編碼”的近義詞。至於為什麼有這個名稱?歷史遺留問題。)

  ANSI code pages:你一定見過ANSI,想想另存文字檔案時。ANSI code pages實際上是一系列的編碼集合,根據作業系統區域設定而啟用其中一種作為預設ANSI編碼。例如公司電腦(英文系統)上的ANSI code page可能是1252,而家裡的中文系統則可能是936。所以在家裡可以用ANSI儲存一個包含中文的文字檔案,在公司則不行。可以在登錄檔鍵:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NLS\CodePage\ACP中檢視到當前使用的ANSI code page。 C#可以通過Encoding.Default檢視。

  OEM code pages: OEM code pages是給控制檯應用程式(如SQLPLUS)使用的。除CJK環境(Chinese-Japanese-Korean)外,Windows使用不同的ANSI code page和OEM code page。例如,公司英文系統上使用的是437。可以使用CHCP命令檢視當前使用的OEM code page, C#可以通過Console.OutputEncoding檢視。

  Code page 1252:

  cp1252字符集:ASCII字符集+若干西歐字元+若干特殊符號,比如™、‰.

  cp1252編碼:使用8位表示一個字元。編碼範圍是[0-255](即Hex[00-FF]),[0-127]部分與ASCII相同,新增的大部分是西歐的字元,例如一些帶上標的字母Â、Ë,以及像這樣一類特殊符號)

  PS1:現實中兩臺PC上的code page資訊

  PC 1:英文版Windows XP,ANSI code page=1252, OEM code page=437

  PC 2:中文版Windows 7,ANSI code page=936, OEM code page=936

  PS2:cp1252與cp437編碼表下載請點選這裡,早期控制檯應用程式常常需要畫一些粗糙的表格等等圖形,所以可以在437中看到不少不同的橫線豎線這一類的特殊符號。

  PS3:CP1252、ISO8859-1、ASCII比較,就實際使用的編碼範圍來說:CP1252>ISO8859-1>ASCII。ASCII是[0-127],CP1252是[0-255],ISO8859-1則移除了cp1252中[0-31]及127這些不可見的控制符,同進移除了[128-159](即Hex[80-9F])中的特殊符號。

Oracle中的編碼與字符集

  (1)為什麼需要兩個字符集?

  Oracle中有兩個字符集:資料庫字符集和國家字符集。

  為什麼要有兩個字符集?如果我知道只需要英文,設定資料庫字符集=US7ASCII,如果我知道只需要西歐字元,設定資料庫字符集=WE8MSWIN1252或者WE8ISO89859P1,或者乾脆就用AL32UTF8。你看,我只需要設定“資料庫字符集”,那麼“國家字符集”有什麼必要呢?

  其實,考慮到歷史遺留問題以及資料庫建立者們無法避免的“短視”,很多現有資料庫都無法支援UNICODE字符集,例如要在現有的US7ASCII資料庫字符集的資料庫中儲存中文,這個時候“國家字符集”+NVARCHAR2這樣的組合就能救你一命了。對於資料型別為NVARCHAR2(以及NCHAR, NCLOB)的欄位,它使用是國家字符集,與資料庫字符集的設定無關。自9i以後,國家字符集可選的只有AL16UTF16與AL32UTF8,UTF-16與UTF-8都是UNICODE編碼標準的實現,因些可以表示世界上幾乎所有的文字。

  當然,如果資料庫字符集本身就使了UNICODE字符集,就沒有必要使用NVARCHAR2, NCHAR, NCLOB這些型別了。

  (2)字符集名稱的玄機

  Oracle對字符集的命名實際上有一定的規則可尋,例如:

  ①AL32UTF8

  【AL】支援所有語言(All Language)。

  【32】每字元最多佔用32位(4位元組)。

  【UTF8】編碼為UTF-8。

  ②WE8MSWIN1252

  【WE】支援西歐語言(Western Europe)。

  【8】每字元需要佔用8位(單位元組)。

  【MSWIN1252】編碼為CP1252。

  ③US7ASCII

  【US】表示美國(United States)。

  【7】每字元需要佔用7位。

  【ASCII】編碼為ASCII。

  其它如ZHS16GBK,ZHT16BIG5,US8PC437(編碼為OEM cp437),都可以類推。

  (3)例子很重要

①準備兩個資料庫

  上帝說要有例子,於是有了兩個相同版本的資料庫,A跟B:

SELECT parameter, VALUE
FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET''NLS_NCHAR_CHARACTERSET')

--資料庫A:PARAMETER                      VALUE
------------------------------ -------------------NLS_CHARACTERSET               WE8MSWIN1252
NLS_NCHAR_CHARACTERSET         AL16UTF16

--資料庫B:PARAMETER                      VALUE
------------------------------ ----------------- NLS_CHARACTERSET               AL32UTF8
NLS_NCHAR_CHARACTERSET         AL16UTF16

--在A和B中分別建立一張表。CREATE TABLE charset_test 
(id NUMBER(4PRIMARY KEY,
vc VARCHAR2(20),
nvc NVARCHAR2(20));

   ②工具很重要

  在測試之前,為避免工具本身的特性給人造成的困惑,介紹一下幾個客戶端工具對UNICODE 的支援情況:

  SQLPLUS:不支援UNICODE字符集。是否支援中文取決於當前的OEM code page,如果是cp437,無論輸入還是顯示中文都是不可能的。但如果是cp936,則可以支援中文輸入輸出。

  PLSQL Developer:7.0版本的查詢結果視窗支援UNICODE字符集,但是編輯視窗(即輸入SQL語句的視窗)不支援。8.0版完全支援UNICODE。

  Oracle SQL Developer:查詢結果視窗與編輯視窗都支援UNICODE字符集。

  ③出現亂碼了

  這裡使用Oracle SQL Developer,分別在A、B中插入並查詢中文:

INSERT INTO charset_test VALUES(1,'','');
COMMIT;

--A庫SELECT * FROM charset_test;
1     ¿     ¿

--B庫SELECT * FROM charset_test;
1     中    中

  暫時先跳過VARCHAR2欄位,先來關注NVARCHAR2欄位,為什麼在A庫不能正常顯示?無非有這幾種可能:

  客戶端作業系統不支援顯示中文。

  Oracle客戶端工具(這裡是Oracle SQL Developer)不支援顯示中文。

  Oracle客戶端有相關設定(比如NLS_LANG)不正確。

  儲存在資料庫中的資料已經是不正確的資料。

  第一點,客戶端作業系統是否支援中文對運行於其上的應用程式有影響嗎?應該有兩種情況,一種是應用程式依賴於作業系統的中文支援;另一種是有一些軟體自己帶有語言包及字型(比如Adobe的一些產品,.NET程式在編譯的時候也可以選擇將字型檔案打包進去),那麼它應該不依賴於作業系統。

  我猜測Oracle SQL Developer應該是屬於前一種,同時我檢查了作業系統,確定其已經支援東亞語言(Control panel—Regional and language options—Language tab—Supplemental languages support—Install files for East Asian languages,如果checkbox已經選中,說明已經安裝東亞語言包)。

  第二點,無論查詢結果視窗還是編輯視窗都支援UNICODE字符集。

  第三點,由於不依賴於Oracle client的OCI,客戶端登錄檔中的NLS_LANG設定對像Oracle SQL Developer沒有影響。

  第四點,我們藉助DUMP()函式來確定NVARCHAR2欄位中具體的內容。

  DUMP()的語法:DUMP([,[,[,]]])

  其中的format引數:如果是8則表示結果使用8進製表示,如果是16則表示16進位制,如果是0到16間的其它數則都使用10進位制。如果是大於16的數,則分幾種情況:如果是可見的ASCII字元則直接列印此字元,如果是控制字元則列印成“^x”,其它情況則把結果按16進位制顯示。為format加上1000則表示除了輸出結果之外,還會附帶輸出所使用的字符集資訊。

  這裡我們使用:

SELECT DUMP(nvc,1016FROM charset_test;
--A庫Typ=1 Len=2 CharacterSet=AL16UTF16: 0,bf

--B庫Typ=1 Len=2 CharacterSet=AL16UTF16: 4e,2d

   我們知道“中”字的UTF-16編碼是4E2D,顯然在A庫中儲存的資料已經是不對的,00BF實際上就是一個倒的問號字元,其儲存在資料庫中的原始資料已經不對了,更何況是客戶端的顯示。

  ④找不同

  那麼為什麼兩個庫會不一樣呢?嫌疑很快就落在了資料庫字符集上,因為A和B的區別只在資料庫字符集上,一個是WE8MSWIN1252,另一個是AL32UTF8。經過測試,結論是:

  Oracle SQL Developer忽略NLS_LANG,字串直接以照資料庫字符集進行編碼後由客戶端傳輸到伺服器端。由於A庫資料庫字符集不支援漢字,很不幸地被替換成了預設的BF並最終被儲存到資料庫中,永遠地錯下去。B庫則相反,中文在傳輸的過程中“存活”下來併成功到達伺服器端,最終自動轉換成NVARCHAR2所用的編碼並存儲到庫中。

  ⑤如何讓NVARCHAR2欄位工作

  看起來似乎A庫中的NVARCHAR2欄位永遠也無法正常使用了,並非這樣,對於Oracle SQL Developer,通過一些設定,就可以讓NVARCHAR2可以正常地插入、查詢。

  找到{ORACLE_HOME}\sqldeveloper\sqldeveloper\bin\sqldeveloper.conf(依賴於你的Oracle SQL Developer安裝路徑),新增一行配置:

AddVMOption -Doracle.jdbc.convertNcharLiterals=true

  同時在中文字串前新增“N”字首:

INSERT INTO charset_test VALUES(2,'',N'');
--NVARCHAR2列中的中文不再是亂碼了SELECT * FROM charset_test WHERE id=2;
2     ¿     中

   這個配置起到的作用是這樣的:在INSERT語句從客戶端傳輸到伺服器端之前,Oracle SQL Developer檢測(實際上是JDBC檢測)語句,如果發現“N”字首,則事先將這部分的字串按UTF-16進行編碼得到16進位制串。也就是相當於執行了這個命令:

INSERT INTO charset_test VALUES(2,’中’,UNISTR('\4e2d'));

  C#不需要做特殊的配置來讓NVARCHAR2正常工作,只需要在執行INSERT時使用引數並選擇正確的引數型別選:

cmd.CommandText = "insert into charset_test values(3,:vc,:nvc)";
OracleParameter p1 = new OracleParameter("vc", OracleDbType.Varchar2);
OracleParameter p2 = new OracleParameter("nvc", OracleDbType.NVarchar2);
p1.Value = "中";
p2.Value = "中";
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
cmd.ExecuteNonQuery();

(4)客戶端的NLS_LANG設定及編碼轉換

  前面我說過Oracle SQL Developer忽略客戶端NLS_LANG設定,那麼對於其它的工具呢?(這裡我們主要關注字符集及編碼,不討論NLS_LANG對日期格式、排序方式、數字顯示格式等等的影響)

  SQLPLUS,插入與查詢都依賴於客戶端NLS_LANG設定。通常,客戶端NLS_LANG設定要與當前的OEM Codepage一致,比如US8PC437。

  PL/SQL Developer,插入與查詢都依賴於客戶端NLS_LANG設定。通常,客戶端NLS_LANG設定要與資料庫字符集一致。

  使用SQLPLUS可以清晰地看到Oracle編碼轉換的過程:

  ①在Oracle客戶端向伺服器端提交SQL語句時,Oracle客戶端根據NLS_LANG和資料庫字符集,對從應用程式接傳送過來的字串編碼進行轉換處理。如果NLS_LANG與資料庫字符集相同,不作轉換,否則要轉換成資料庫字符集並傳送到伺服器。伺服器在接收到字串編碼之後,對於普通的CHAR或VARCHAR2型別,直接儲存;對於NCHAR或NVARCHAR2型別,伺服器端將其轉換為國家字符集再儲存。

  

  ②在查詢資料時,伺服器端原樣返回儲存在庫中的資料,由客戶端根據返回的元資料中的字符集資訊與NLS_LANG和NLS_NCHAR的設定進行比較(如果NLS_NCHAR沒有設定,則其預設值為NLS_LANG中的字符集設定),如果元資料中的字符集資訊與客戶端設定一致,不進行轉換,否則要進行轉換。國家字符集的轉換根據NLS_NCHAR設定進行轉換。

  

  這裡我也舉幾個使用SQLPLUS的測試例子,分別在A、B兩庫執行相同的語句,然後通過網路抓包檢視從Oracle client傳輸到伺服器的具體內容。

  例1 客戶端NLS_LANG:WE8MSWIN1252

  SQL命令:

insert into charset_test values(1,'æ',null);

  網路抓包(A庫,資料庫字符集為WE8MSWIN1252):91

  解釋:由於應用程式(即SQLPLUS)使用的編碼是Codepage437,所以æ的編碼是91。當91被傳給Oracle client後,Oracle client根據NLS_LANG誤判其使用的編碼是Codepage1252,又由於NLS_LANG設定與資料庫字符集一致,於是Oracle client不進行編碼轉換,91被直接傳給伺服器並存儲,考慮到資料庫字符集是Codepage1252,很顯然91是錯誤的資料(字元[æ]在Codepage1252下的編碼是E6,而非91)。

  這個錯誤導致了一個有趣的現象,那就是在同一個客戶端使用SQLPLUS查詢居然可以看到正確字元[æ],這是由於SELECT的時候91也被直接返回,並且在Oracle client也不進行編碼轉換而是直接傳給了應用程式,恰巧應用程式根據自己使用的編碼可以正確解析91。但是換一個客戶端機器,或者換一個客戶端工具都可能得到不一樣的查詢結果。

  網路抓包(B庫,資料庫字符集為AL32UTF8):E2 80 98

  解釋:由於應用程式(即SQLPLUS)使用的編碼是Codepage437,所以æ的編碼是91。當91被傳給Oracle client後,Oracle client根據NLS_LANG誤判其使用的編碼是Codepage1252,而91在Codepage1252中對應的是字元[‘],根據Codepage1252到資料字符集UTF8的轉換,最終轉換成了E2 80 98,即UTF8下的[‘]。

  例2 客戶端NLS_LANG:US7ASCII

  SQL命令:

insert into charset_test values(1,'æ',null);

  網路抓包(A庫):BF

  解釋:由於應用程式(即SQLPLUS)使用的編碼是Codepage437,所以æ的編碼是91。當91被傳給Oracle client後,Oracle client根據NLS_LANG誤判其使用的編碼是ASCII,而91在ASCII中是無效編碼,根據ASCII到資料字符集Codepage1252的轉換,最終轉換成了BF,BF是Codepage1252遇到無效編碼時使用的預設替換編碼。

  網路抓包(B庫): EF BF BD

  解釋:由於應用程式(即SQLPLUS)使用的編碼是Codepage437,所以æ的編碼是91。當91被傳給Oracle client後,Oracle client根據NLS_LANG誤判其使用的編碼是ASCII,而91在ASCII中是無效編碼,根據ASCII到資料字符集UTF8的轉換,最終轉換成了EF BF BD,EF BF BD是UTF8遇到無效編碼時使用的預設替換編碼。

  例3 客戶端NLS_LANG:US8PC437

  SQL命令:

insert into charset_test values(1,'æ',null);

  網路抓包(A庫):E6

  解釋:E6是字元[æ]的正確的Codepage1252編碼,此次由於應用程式(即SQLPLUS)使用的是Codepage437,Oracle client從NLS_LANG獲得的編碼資訊也是Codepage437,於是進行了正確的編碼轉換。

  網路抓包(B庫):C3 A6

  解釋:C3 A6是字元[æ]的正確的UTF8編碼,此次由於應用程式(即SQLPLUS)使用的是Codepage437,Oracle client從NLS_LANG獲得的編碼資訊也是Codepage437,於是進行了正確的編碼轉換。

  我覺得,只有SQLPLUS的日子總是那麼美好,一切看起來既合理又可解釋。當其它工具出現之後,世界就變得一團亂麻了,Oracle SQL Developer完全忽略客戶端NLS_LANG設定倒是讓事情變得簡單,不過PL/SQL Developer則是另一回事,我花了4天時間企圖搞明白其中的編碼轉換過程,最終只證明它就是個不可理喻的玩意兒,唯一目前看起來還正確的結論是:如果要用PL/SQL Developer,只好還是把NLS_LANG設定得跟資料庫字符集一致。其它就只能自求多福了。

  (5)NLS_LANG對ODP.NET的影響

  唯一受客戶端NLS_LANG影響的是OracleString的GetNonUnicodeBytes()方法,此方法依賴於客戶端本地設定的字符集,例如我們把NLS_LANG從AMERICAN_AMERICA.WE8MSWIN1252改成AMERICAN_AMERICA.US7ASCII

  其中230(即HexE6)正是字元‘æ’的編碼,而63(即Hex3F)是ASCII中的問號(由於ASCII字符集中沒有‘æ’,故用問號代替)。

  (6)關於VARCHAR2, NVARCHAR2的其它問題

  NVARCHAR2(N),其中的N是指字元數,不是位元組數。不過其最大長度是以位元組為單位,即4000位元組。

  VARCHAR2(N),其中的N可能是指字元數,也可能是指位元組數。你可以顯式地在宣告的時候指定,比如VARCHAR2(10 BYTE)或者VARCHAR2(10 CHAR),未顯式指明時,則由引數NLS_LENGTH_SEMANTICS決定。需要注意的是你能成功宣告VARCHAR2(4000 CHAR)並不能保證你能真的儲存4000個字元,如果超過4000位元組,該報錯Oracle還是會報錯