UCS只是規(guī)定如何編碼,并沒(méi)有規(guī)定如何傳輸、保存這個(gè)編碼。
例如“漢”字的UCS編碼是6C49,我可以用4個(gè)ASCII數(shù)字來(lái)傳輸、保存這個(gè)編碼;也可以用UTF-8編碼:3個(gè)連續(xù)的字節(jié)E6 B1 89來(lái)表示它。關(guān)鍵在于通信雙方都要認(rèn)可。
UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個(gè)特別的好處是它與ISO-8859-1完全兼容。
UTF是“UCS Transformation Format”的縮寫(xiě)。UCS可以看作是"Unicode Character Set"的縮寫(xiě)。
UTF-8就是以8位為單元對(duì)UCS進(jìn)行編碼。
---------------
內(nèi)碼和"code page"
---------------
目前Windows的內(nèi)核已經(jīng)支持Unicode字符集,這樣在內(nèi)核上可以支持全世界所有的語(yǔ)言文字。
但是由于現(xiàn)有的大量程序和文檔都采用了某種特定語(yǔ)言的編碼,例如GBK,Windows不可能不支持現(xiàn)有的編碼,而全部改用Unicode。Windows使用代碼頁(yè)("code page")來(lái)適應(yīng)各個(gè)國(guó)家和地區(qū)。"code page"可以被理解為前面提到的內(nèi)碼。GBK對(duì)應(yīng)的"code page"是CP936。
微軟也為GB18030定義了"code page":CP54936。但是由于GB18030有一部分4字節(jié)編碼,而Windows的代碼頁(yè)只支持單字節(jié)和雙字節(jié)編碼,所以這個(gè)"code page"是無(wú)法真正使用的。
----------------
UTF的字節(jié)序和BOM
----------------
UTF-8以字節(jié)為編碼單元,沒(méi)有字節(jié)序的問(wèn)題。
UTF-16以兩個(gè)字節(jié)為編碼單元,在解釋一個(gè)UTF-16文本前,首先要弄清楚每個(gè)編碼單元的字節(jié)序。例如“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節(jié)流“594E”,那么這是“奎”還是“乙”?
Unicode規(guī)范中推薦的標(biāo)記字節(jié)順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一個(gè)有點(diǎn)小聰明的想法:在UCS編碼中有一個(gè)叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實(shí)際傳輸中。UCS規(guī)范建議我們?cè)趥鬏斪止?jié)流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個(gè)字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個(gè)字節(jié)流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來(lái)表明字節(jié)順序,但可以用BOM來(lái)表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗(yàn)證一下)。所以如果接收者收到以EF BB BF開(kāi)頭的字節(jié)流,就知道這是UTF-8編碼了。Windows就是使用BOM來(lái)標(biāo)記文本文件的編碼方式的。
--------
關(guān)于內(nèi)碼
--------
內(nèi)碼是指操作系統(tǒng)內(nèi)部的字符編碼。早期操作系統(tǒng)的內(nèi)碼是與語(yǔ)言相關(guān)的。
現(xiàn)在的Windows在系統(tǒng)內(nèi)部支持Unicode,然后用代碼頁(yè)適應(yīng)各種語(yǔ)言,“內(nèi)碼”的概念就比較模糊了。
微軟一般將缺省代碼頁(yè)指定的編碼說(shuō)成是內(nèi)碼。
內(nèi)碼這個(gè)詞匯,并沒(méi)有什么官方的定義,代碼頁(yè)也只是微軟這個(gè)公司的叫法。作為程序員,我們只要知道它們是什么東西,沒(méi)有必要過(guò)多地考證這些名詞。
所謂代碼頁(yè)("code page")就是針對(duì)一種語(yǔ)言文字的字符編碼。例如GBK的"code page"是CP936,BIG5的"code page"是CP950,GB2312的"code page"是CP20936。
Windows中有缺省代碼頁(yè)的概念,即缺省用什么編碼來(lái)解釋字符。例如Windows的記事本打開(kāi)了一個(gè)文本文件,里面的內(nèi)容是字節(jié)流:BA、BA、D7、D6。Windows應(yīng)該去怎么解釋它呢?
是按照Unicode編碼解釋、還是按照GBK解釋、還是按照BIG5解釋,還是按照ISO8859-1去解釋?如果按GBK去解釋,就會(huì)得到“漢字”兩個(gè)字。按照其它編碼解釋,可能找不到對(duì)應(yīng)的字符,也可能找到錯(cuò)誤的字符。所謂“錯(cuò)誤”是指與文本作者的本意不符,這時(shí)就產(chǎn)生了亂碼。
答案是Windows按照當(dāng)前的缺省代碼頁(yè)去解釋文本文件里的字節(jié)流。缺省代碼頁(yè)可以通過(guò)控制面板的區(qū)域選項(xiàng)設(shè)置。記事本的另存為中有一項(xiàng)ANSI,其實(shí)就是按照缺省代碼頁(yè)的編碼方法保存。
Windows的內(nèi)碼是Unicode,它在技術(shù)上可以同時(shí)支持多個(gè)代碼頁(yè)。只要文件能說(shuō)明自己使用什么編碼,用戶又安裝了對(duì)應(yīng)的代碼頁(yè),Windows就能正確顯示,例如在HTML文件中就可以指定charset。
有的HTML文件作者,特別是英文作者,認(rèn)為世界上所有人都使用英文,在文件中不指定CharSet。如果他使用了0x80-0xff之間的字符,中文Windows又按照缺省的GBK去解釋,就會(huì)出現(xiàn)亂碼。這時(shí)只要在這個(gè)html文件中加上指定CharSet的語(yǔ)句,例如:
如果原作者使用的代碼頁(yè)和ISO8859-1兼容,就不會(huì)出現(xiàn)亂碼了。
再說(shuō)區(qū)位碼,啊的區(qū)位碼是1601,寫(xiě)成16進(jìn)制是0x10,0x01。這和計(jì)算機(jī)廣泛使用的ASCII編碼沖突。為了兼容00-7f的ASCII編碼,我們?cè)趨^(qū)位碼的高、低字節(jié)上分別加上A0。這樣“啊”的編碼就成為B0A1。我們將加過(guò)兩個(gè)A0的編碼也稱為GB2312編碼,雖然GB2312的原文根本沒(méi)提到這一點(diǎn)。
為了識(shí)別 Unicode 文件,Microsoft 建議所有的 Unicode 文件應(yīng)該以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符開(kāi)頭。這作為一個(gè)“特征符”或“字節(jié)順序標(biāo)記(byte-order mark,BOM)”來(lái)識(shí)別文件中使用的編碼和字節(jié)順序。
但是,Linux/UNIX 并沒(méi)有使用 BOM,因?yàn)樗鼤?huì)破壞現(xiàn)有的 ASCII 文件的語(yǔ)法約定。在 POSIX 系統(tǒng)中,選中的語(yǔ)言環(huán)境識(shí)別了在一個(gè)過(guò)程中的所有輸入輸出文件期望的編碼形式。
最近在做的廣告系統(tǒng)中,碰到了一個(gè)問(wèn)題,廣告系統(tǒng)采用的UTF-8編碼,而一些使用這套廣告系統(tǒng)的頻道頁(yè)面使用的是GB2312編碼。當(dāng)然也有使用UTF-8編碼的頻道使用這套廣告系統(tǒng)。
頻道頁(yè)面是通過(guò)嵌入類似如下的代碼方式,來(lái)調(diào)用廣告的。具體那個(gè)時(shí)間顯示那個(gè)廣告,或者那些廣告組合是廣告系統(tǒng)自己處理的。
<script type="text/javascript">< span="">script><script type="text/javascript" src="http://ads.csdn.net/AD/Show_JavaScript_AD.js" >< span="">script>
不同編碼的頁(yè)面、腳本之間互相引用,就會(huì)產(chǎn)生亂碼的問(wèn)題,解決方法就是統(tǒng)一成一種編碼。
asp.net 中,如果要修改輸出頁(yè)面的編碼,可以通過(guò)修改web.config中以下配置信息
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
以上只是修改整體的默認(rèn)編碼,如果只有某個(gè)頁(yè)的編碼需要修改,ASP.net 中則可以簡(jiǎn)單的使用下面代碼:
Encoding gb2312 = Encoding.GetEncoding("gb2312");Response.ContentEncoding = gb2312;
在非ASP.net 應(yīng)用中,可能你讀到的數(shù)據(jù)是UTF-8編碼,但是你要轉(zhuǎn)換為GB2312編碼,則可以參考以下代碼:
string utfinfo = "document.write(\"alert(‘aa你好么??‘);\");";string gb2312info = string.Empty;Encoding utf8 = Encoding.UTF8;Encoding gb2312 = Encoding.GetEncoding("gb2312");// Convert the string into a byte[].byte[] unicodeBytes = utf8.GetBytes(utfinfo);// Perform the conversion from one encoding to the other.byte[] asciiBytes = Encoding.Convert(utf8, gb2312, unicodeBytes);// Convert the new byte[] into a char[] and then into a string.// This is a slightly different approach to converting to illustrate// the use of GetCharCount/GetChars.char[] asciiChars = new char[gb2312.GetCharCount(asciiBytes, 0, asciiBytes.Length)];gb2312.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);gb2312info = new string(asciiChars);
當(dāng)然,其他各種編碼之間的轉(zhuǎn)換,跟上述代碼也類似的,就不描述了。
有一個(gè)Web項(xiàng)目,Web.Config中requestEncoding和responseEncoding都是gb2312,而從數(shù)據(jù)庫(kù)中取出的簡(jiǎn)介數(shù)據(jù)可能是中文和韓、日文混合的內(nèi)容,這時(shí)候如果直接輸出到頁(yè)面上,其頁(yè)面會(huì)出現(xiàn)亂碼,其中的韓文內(nèi)容無(wú)法正確顯示。當(dāng)然如果項(xiàng)目的編碼都使用Utf-8的話將沒(méi)有這個(gè)問(wèn)題,但這個(gè)項(xiàng)目是一個(gè)老項(xiàng)目,為了盡量不要影響已有的程序,所以無(wú)法將編碼改為Utf-8,只能在本頁(yè)面上動(dòng)腦筋。
經(jīng)過(guò)研究,發(fā)現(xiàn)這個(gè)問(wèn)題可以通過(guò)Html實(shí)體的方法解決。
對(duì)于Html實(shí)體請(qǐng)參考:
Character entity references in HTML 4
測(cè)試代碼:
Byte[] bComments = Encoding.UTF8.GetBytes("一ンブル????中文");
char[] cComments = Encoding.UTF8.GetChars(bComments);
StringBuilder charBuilder = new StringBuilder();
foreach(char c in cComments)
{
if(c > ‘\u0800‘)
{
charBuilder.Append("&#");
charBuilder.Append((int)c);
}
else
{
charBuilder.Append(c);
}
}
Response.Write(charBuilder.ToString());
這段代碼的作用是將所有的中文、韓文、日文字符通過(guò)硬編碼輸出成為html實(shí)體。而Html實(shí)體是不受ResponseEncoding和頁(yè)面編碼集影響的。
說(shuō)明:
\u0800 以上的為中、韓、日字符。
中文的范圍:\u4e00 - \u9fa5,日文在\u0800 - \u4e00,韓文為\u9fa5以上。
這個(gè)方法僅僅是為了解決小范圍問(wèn)題,如果各位有更好的辦法請(qǐng)指教。
ms的Best Practices Analyzer Tool for Microsoft SQL Server 2000 1.0上個(gè)月發(fā)布了1.0版本,和beta版相比,看起來(lái)沒(méi)有什么太大的變化。Best Practices Analyzer Tool for Microsoft SQL Server 2000檢查的一些rules可以做為t-sql編程的checklist
sql server數(shù)據(jù)庫(kù)編程指導(dǎo)以及最佳實(shí)踐
原則
編寫(xiě)高可讀的代碼:遵循命名原則和代碼風(fēng)格約定
開(kāi)始就要關(guān)注t-sql代碼性能的影響:減少網(wǎng)絡(luò)流量,減少磁盤(pán)IO,利用索引,避免lock
編寫(xiě)安全的代碼
------------------------------------------------------------------------------
命名數(shù)據(jù)庫(kù)對(duì)象時(shí),采用統(tǒng)一的前綴或者后綴
采用統(tǒng)一的前綴或者后綴是為了提高代碼的可讀性,但是
存儲(chǔ)過(guò)程不要使用sp_作為前綴,函數(shù)不要使用fn_作為前綴。
如果sql server發(fā)現(xiàn)存儲(chǔ)過(guò)程以sp_作為前綴,都會(huì)先到master數(shù)據(jù)庫(kù)中查詢這個(gè)存儲(chǔ)過(guò)程
添加必要的注釋
存儲(chǔ)過(guò)程或者函數(shù),視圖前應(yīng)該注釋創(chuàng)建者, 創(chuàng)建時(shí)間,修改者,修改時(shí)間,功能注釋,使用說(shuō)明,同時(shí)包含一到多條執(zhí)行該對(duì)象的語(yǔ)句
及時(shí)檢查執(zhí)行狀況
默認(rèn)情況下,如果一條sql語(yǔ)句執(zhí)行錯(cuò)誤,sql server不會(huì)自動(dòng)roll back前面的執(zhí)行(可以設(shè)置:SET XACT_ABORT ON),sql語(yǔ)句執(zhí)行完畢后,需要及時(shí)通過(guò)全局變量@@error和@@rowcount來(lái)檢查執(zhí)行狀況。
用標(biāo)準(zhǔn)的join方式
標(biāo)準(zhǔn)的join方式是指while語(yǔ)句中只包含過(guò)濾條件,不包含join條件
盡量避免客戶端程序直接通過(guò)select,insert,update等直接操作數(shù)據(jù)庫(kù)
用存儲(chǔ)過(guò)程封裝數(shù)據(jù)訪問(wèn),存儲(chǔ)過(guò)程是經(jīng)過(guò)編譯的,不用每次計(jì)算execute plan。而且封裝了邏輯,同時(shí)增加了安全性。
存儲(chǔ)過(guò)程如果需要返回?cái)?shù)據(jù),使用output關(guān)鍵字
不要用return返回?cái)?shù)據(jù),存儲(chǔ)過(guò)程的return應(yīng)該返回存儲(chǔ)過(guò)程的執(zhí)行狀況,如果需要返回?cái)?shù)據(jù),使用帶有output關(guān)鍵字的參數(shù)
謹(jǐn)慎使用IDENTITY作為表的主鍵的數(shù)據(jù)類型
IDENTITY會(huì)給客戶端程序和database交互帶來(lái)很多影響,而且在數(shù)據(jù)導(dǎo)入導(dǎo)出時(shí)也會(huì)帶來(lái)麻煩,需要仔細(xì)評(píng)估這些影響。但是IDENTITY和guid相比也有優(yōu)點(diǎn),就是可讀性。
盡量避免使用NULL
如果沒(méi)有特別設(shè)置,null參與的運(yùn)算結(jié)果都為null,如果疏忽這一原則,會(huì)對(duì)程序邏輯的正確性帶來(lái)影響,而且,客戶端程序需要額外的步驟來(lái)處理NULL。需要設(shè)置ANSI_NULLS為ON。
在insert語(yǔ)句中,使用確定的列名
insert語(yǔ)句中,使用確定的列名以間少表結(jié)構(gòu)變化對(duì)t-sql代碼帶來(lái)的影響
盡量使用外鍵,約束檢查來(lái)保證數(shù)據(jù)的完整性
數(shù)據(jù)完整性至關(guān)重要,外鍵,約束檢查可以避免另外寫(xiě)代碼來(lái)保證數(shù)據(jù)完整性
不要在查詢時(shí)用select * ,用確定的列名來(lái)代替 *
查詢結(jié)果中冗余的信息影響整體的性能
盡量避免使用服務(wù)器端游標(biāo)
服務(wù)器端游標(biāo)對(duì)性能有嚴(yán)重的影響,應(yīng)當(dāng)盡量避免,比如可以用while循環(huán)來(lái)代替游標(biāo),如果不能避免,則應(yīng)選擇最合適的游標(biāo)類型
盡量避免使用臨時(shí)表
臨時(shí)表會(huì)發(fā)生磁盤(pán)IO操作,影響性能,可以用嵌套查詢,view,或者table變量來(lái)代替臨時(shí)表。如果需要緩存大量的數(shù)據(jù),臨時(shí)表優(yōu)于table變量,同時(shí)注意為臨時(shí)表建index
如果需要執(zhí)行一系列sql命令,在前面添加SET NOCOUNT ON
執(zhí)行SET NOCOUNT ON,sql命令執(zhí)行影響的行數(shù)不會(huì)傳回客戶端,減少網(wǎng)絡(luò)流量,提高性能
在字符串匹配查詢時(shí),避免在第一個(gè)字符位置使用通配符
如果第一個(gè)字符位置使用通配符,則index不起作用
避免使用IN 或者NOT IN
使用IN 或者NOT IN,則index不起作用
事務(wù)處理時(shí),盡可能的占用最少的資源
事務(wù)處理時(shí),盡可能的占用最少的資源以減少資源的鎖定,提高數(shù)據(jù)庫(kù)整體性能。同時(shí)檢查加鎖類型,盡量使用低級(jí)別的加鎖類型。
匹配的事務(wù)處理
如果存儲(chǔ)過(guò)程開(kāi)始了事務(wù)處理,應(yīng)該負(fù)責(zé)結(jié)束這個(gè)事物處理,submit或者rollback
操作NCHAR或者NVARCHAR數(shù)據(jù)類型的列時(shí),使用N關(guān)鍵字
使用N關(guān)鍵字,sql server會(huì)使用unicode編碼,避免出現(xiàn)亂碼
盡量避免使用TEXT,NTEXT,binary,image數(shù)據(jù)類型的字段,盡量避免將文件或者圖片直接存入數(shù)據(jù)庫(kù)
這些數(shù)據(jù)類型訪問(wèn)方式不同于普通的數(shù)據(jù)類型。數(shù)據(jù)庫(kù)也不是存儲(chǔ)文件或者圖片內(nèi)容合適的地方
盡量使用VARCHAR代替CHAR,用NVARCHAR代替VARCHAR,
用VARCHAR代替CHAR是為了節(jié)省數(shù)據(jù)庫(kù)空間,NVARCHAR代替VARCHAR是為了避免unicode帶來(lái)的麻煩
如果某個(gè)table中的數(shù)據(jù)對(duì)不同用戶的可見(jiàn)性是不一樣的,使用view來(lái)隔離用戶對(duì)table的直接訪問(wèn)
檢查sql注入式攻擊對(duì)代碼的影響。
聯(lián)系客服