之前一直困惑為什么數據庫字符集和客戶端字符集是一致的但是當數據庫插入到表里卻成了亂碼,今天在群里看見一位前輩講解了這個問題,因此也就跟著做了一個實驗驗證下,結果發現了其中的奧秘:
1) 如果恰巧數據庫的字符集也是UTF8, 那么Oracle就不作任何轉換直接插入到數據中.
2) 如果數據庫的字符集是ZHS16GBK, 那么Oracle會根據內部的MAP,按UTF8截取客戶端發來的字符串, 轉換成ZHS16GBK
3)如果您指定NLS_LANG是utf8, 但是, 輸入的卻是zhs16gbk的編碼, 那么Oracle也會不作任何轉換, 將ZHS16GBK的字符編碼直接存入數據庫. --這叫garbage-in--garbage-out
4)如果數據庫的字符是AL32UTF8, 您指定NLS_LANG為ZHS16GBK, 但是, 您真正輸入的是UTF8的字符, 那么,Oracle會把您輸入的UTF8字符當作ZHS16GBK字符轉換為UTF8存入數據庫. 這種情況會出現亂碼。
5)之前的客戶端字符集一定要和服務器字符集一致或者是超集才不會出現亂碼,這個結論是片面的,本實驗GBK和utf8他們不是超集關系,但是存入之后也顯示正常。
結論:
1.)數據庫字符集(創建的時候設置的,后期沒事別自己去update props$)
2.)客戶端字符集NLS_LANG(數據庫機器上你設置的環境變量 echo $NLS_LANG)
3.)個人工具連接到服務器上,工具(putty/securecrt等等各種SSH客戶端等等)設置的字符集,保證客戶端字符集 NLS_LANG 和 個人工具顯示的字符集一致,并且這個字符集是可以正常轉換為數據庫字符集就OK
[oracle@hxy ~]$ sqlplus / as sysdba
SQL*Plus: Release 10.2.0.1.0 - Production on Wed Mar 26 10:53:59 2014
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options
SQL> col parameter for a30
SQL> col value for a30
查找數據字符集的語句如下:
SQL> 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
20 rows selected.
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64 bit Production
With the Partitioning, OLAP and Data Mining options
實驗一:數據庫字符集,客戶端字符集,個人工具字符集一致
1)設置NLS_LANG為ZHS16GBK
[oracle@hxy ~]$ export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
2)把個人工具的編碼也設置成ZHS16GBK
3)連接數據庫,插入數據
[oracle@hxy ~]$ sqlplus / as sysdba
SQL>insert into t2 values('ZHS16GBK','ZHS16GBK','中國');
SQL> select * from t2;
NLS_LANG INPUT_CHARSET C1
-------------------- -------------------- --------------------
ZHS16GBK ZHS16GBK 中國
SQL> select c1,dump(c1,16) from t2;
C1 DUMP(C1,16)
-------------------- --------------------------------------------------------------------------------
中國 Typ=1 Len=4: d6,d0,b9,fa ZHS16GBK編碼是2位
此時編碼顯示正常, 如果恰巧數據庫的字符集也是ZHS16GBK, 那么Oracle就不作任何轉換直接插入到數據中.
4)把個人工具編碼設置成UTF8,之后向數據庫里插入數據
SQL> insert into t2 values('ZHS16GBK','UTF8','中國');
1 row created.
SQL> commit ;
Commit complete.
SQL> select * from t2;
NLS_LANG INPUT_CHARSET C1
-------------------- -------------------- --------------------
ZHS16GBK ZHS16GBK ▒й▒ 此處顯示了亂碼
ZHS16GBK UTF8 中國 后插入的數據正常顯示
SQL> select c1, input_charset,dump(c1,16) from t2;
C1 INPUT_CHARSET DUMP(C1,16)
-------------------- ------------------------- -------------------------------------------------------
▒й▒ ZHS16GBK Typ=1 Len=4: d6,d0,b9,fa
中國 UTF8 Typ=1 Len=6: e4,b8,ad,e5,9b,bd
用下dump函數查看后發現存入的編碼長度改變utf8的3位的了
原文轉自:http://blog.csdn.net/haoxiaoyan/article/details/22165465