西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁西西教程數(shù)據(jù)庫教程 → mysql中文亂碼的一些解決方案

mysql中文亂碼的一些解決方案

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來源:西西整理時(shí)間:2015/1/11 1:51:49字體大。A-A+

作者:西西點(diǎn)擊:242次評(píng)論:0次標(biāo)簽: mysql

  • 類型:電子教程大小:8.5M語言:中文 評(píng)分:8.3
  • 標(biāo)簽:
立即下載

 我們自己鼓搗mysql時(shí),總免不了會(huì)遇到這個(gè)問題:插入中文字符出現(xiàn)亂碼,雖然這是運(yùn)維先給配好的環(huán)境,但是在自己機(jī)子上玩的時(shí)候咧,總得知道個(gè)一二吧,不然以后如何優(yōu)雅的吹牛B。

如果你也遇到了這個(gè)問題,咱先不談原因,在PC自帶的cmd中(或者是mysql安裝版安裝后的Command Line客戶端,又或者是工作用的SecureCRT)試試效果。進(jìn)入mysql環(huán)境,從頭開始操作。假設(shè)你的客戶端編碼是gbk或者utf8(這么說太不嚴(yán)謹(jǐn)了,怎么能假設(shè)呢,但是一般來說假如安裝后沒動(dòng)過,cmd是gbk編碼,mysql安裝后的Command Line客戶端沒裝不記得,CRT看看Session Options里面的編碼設(shè)置,一般也會(huì)設(shè)置成utf8),執(zhí)行一些語句:

1. 設(shè)置編碼客戶端、連接、返回結(jié)果的字符集,先設(shè)置成latin1,

2. 然后執(zhí)行下面的看下各個(gè)字符是不是這樣的,

如果你的character_set_client、character_set_connection、character_set_results不是latin1,可以這樣執(zhí)行,把他們單個(gè)分別設(shè)置成latin1,比如設(shè)character_set_client,其他兩個(gè)一樣,確保這三個(gè)均是latin1(第一步的sql語句實(shí)際做的就是這件事),

 

3. 單獨(dú)創(chuàng)建一個(gè)數(shù)據(jù)庫db_latin1,當(dāng)然是很簡(jiǎn)單的了,測(cè)試嘛,創(chuàng)建時(shí)就設(shè)置數(shù)據(jù)庫的編碼的為latin1,

 

4. 在它下面創(chuàng)建一張表tab_latin1,字符集也設(shè)置成latin1,這里不設(shè)置字符也行,數(shù)據(jù)庫級(jí)已經(jīng)設(shè)置了,這里只創(chuàng)建一個(gè)name字段,

5. 插入一些中文字符到表中,先說明,本機(jī)的cmd編碼是gbk,查看方法是右鍵屬性->選項(xiàng),看下當(dāng)前代碼頁即可知道,

6. 查看下結(jié)果

看吧,正常顯示中文了~~~

OK,都到這兒了你就不想知道“為什么我那樣設(shè)置就是不行”么,當(dāng)然得往下看看是不。上圖:

我們知道m(xù)ysql是客戶端-服務(wù)器軟件,每次操作都是客戶端向服務(wù)端發(fā)送請(qǐng)求,然后可能會(huì)返回一些結(jié)果,這之間插入的字符經(jīng)過了一系列轉(zhuǎn)換。首先供我們編輯的客戶端本身就有一種編碼,比如PC端的命令行默認(rèn)是gbk,PC自帶notepad新建文本文件默認(rèn)是ANSI,常用的文本編輯器如notepad++,我們可能會(huì)設(shè)置默認(rèn)編碼為utf8,就是說在編輯器上編輯,你所看到的本身就是一種編碼了。

1. 在客戶端編輯后,首先轉(zhuǎn)化為client對(duì)應(yīng)的字符集,即上面打印出的character_set_client變量指示的字符集;

2. 向數(shù)據(jù)庫服務(wù)發(fā)送請(qǐng)求,發(fā)送過程中,轉(zhuǎn)化為connection對(duì)應(yīng)連接字符集,即character_set_connection變量對(duì)應(yīng)字符集;

3. 存儲(chǔ)到數(shù)據(jù)庫中,轉(zhuǎn)化為數(shù)據(jù)庫存儲(chǔ)的字符集,可能是server級(jí)別(character_set_server)、database級(jí)別(character_set_database)或者表級(jí)別和列級(jí)別(這里還要細(xì)說下);

4. 數(shù)據(jù)庫收到請(qǐng)求,執(zhí)行查詢得到結(jié)果,再次轉(zhuǎn)化為results對(duì)應(yīng)字符集,即character_set_results變量所指,該結(jié)果返回到客戶端上;

5. 結(jié)果來了,是按照results字符集編碼的,那我們讓這個(gè)結(jié)果顯示的客戶端工具它支持什么樣的編碼也很重要,這決定了它如何去解碼結(jié)果。假如這個(gè)結(jié)果是utf8編碼,返回給某客戶端了,但這個(gè)客戶端只有ANSI編碼,那當(dāng)然不能顯示正常,比如它返回到SecureCRT,結(jié)果顯示不正常,但是CRT支持多種編碼,我們手動(dòng)將它調(diào)成utf8編碼,那它就又顯示正常了,所以嚴(yán)格來說這一步算不上,只是跟客戶端條件有關(guān),畢竟當(dāng)我們知道后將客戶端調(diào)整成正常的編碼或者本來就支持轉(zhuǎn)換results的編碼后,這一步就不存在了。

在上面的第3步中,從連接字符集編碼轉(zhuǎn)化為數(shù)據(jù)庫存儲(chǔ)使用的編碼時(shí),要分幾種情況,一般我們?cè)谘bmysql時(shí),特別是32位安裝版本時(shí),中間有一個(gè)選擇編碼的步驟,大多會(huì)選擇utf8編碼,這時(shí)系統(tǒng)就可能會(huì)把一系列的字符集變量均設(shè)置成了utf8,比如character_set_server、character_set_connection、character_set_database等等。也就是說這個(gè)character_set_server變量在你啟動(dòng)mysql服務(wù)的事先就被設(shè)置好了,我們可以稱它為服務(wù)器級(jí)編碼,那我們?cè)诮ū砬埃鹊脛?chuàng)建數(shù)據(jù)庫,在創(chuàng)建數(shù)據(jù)庫時(shí),我們知道可以顯式指定編碼的,比如最開頭時(shí)我創(chuàng)建時(shí)顯式指定采用latin1字符集,也可以不指定,如果不指定的話,它將采用服務(wù)器級(jí)的字符集,即character_set_server,同理在創(chuàng)建表時(shí),也可不指定編碼,不指定的話,采用數(shù)據(jù)庫級(jí)編碼,級(jí)character_set_database,更加同理在創(chuàng)建表中列字段時(shí)也可指定編碼,不指定編碼的話將采用表級(jí)別字符集,因此有這么一個(gè)繼承關(guān)系在這:

character_set_server => character_set_database => character set in table(無此變量) => character set column(無此變量)

mysql創(chuàng)建表可以細(xì)化到這四個(gè)層次,不是每一層都必須指定,默認(rèn)使用上一級(jí)的字符集(字符校對(duì)規(guī)則也是這樣的,collation,稍后說明)。

那么有沒有可能character_set_server沒有指定呢,如果任何地方都沒指定,特別是非安裝版中,如果忘了,mysql在編譯時(shí)默認(rèn)采用latin1,為了應(yīng)對(duì)這種情況,特別是非安裝版本中在配置mysql時(shí),經(jīng)常需要手動(dòng)配置mysql配置文件mysql.ini,其中就有大概這么一項(xiàng):

在配置文件中默認(rèn)采用的字符集,因此如果指定了character_set_server默認(rèn)就會(huì)采用它,這樣其他層次都不指定的話依次繼承。

其他的,character_set_filesystem:把操作系統(tǒng)上的字符轉(zhuǎn)換成此字符集,即把character_set_client轉(zhuǎn)換成character_set_filesystem,默認(rèn)為binary則不轉(zhuǎn)換,character_set_system:此變量總是utf8,為存儲(chǔ)系統(tǒng)元字符的字符集,如表名、列名、用戶名等,character_set_dir:很明顯是指示一個(gè)目錄的變量,打開這個(gè)目錄,里邊存放的是mysql的各種用于編碼字符集的xml格式文件。以上三個(gè)值在解決亂碼問題時(shí)基本可忽視。

好,轉(zhuǎn)換流程和各變量的含義清楚了,就要搞清楚哪些字符集編碼之間可以轉(zhuǎn)換,能轉(zhuǎn)換可能也是在一定編碼范圍內(nèi)的字符能轉(zhuǎn)換,不至于出現(xiàn)亂碼甚至損壞。損壞了就再也無法正確顯示了,哪怕設(shè)置是正確的,還原是還原不回來的。當(dāng)然關(guān)于字符之間的轉(zhuǎn)化情況很多,字符集有那么多種,隨便兩個(gè)之間都可以轉(zhuǎn)換一下試試,不能一一列舉,可以參考這篇文章:http://www.imcjd.com/?p=1324,它針對(duì)經(jīng)常用到的字符轉(zhuǎn)換作了一些轉(zhuǎn)換比較和測(cè)試。

其中,可以了解到,完全匹配的轉(zhuǎn)換是肯定沒有問題的,比如,gbk->gbk,utf8->utf8,latin1->latin1;轉(zhuǎn)換為單字節(jié)編碼的latin1也沒問題,比如gbk->latin1、utf8->latin1;單字節(jié)編碼(latin1)轉(zhuǎn)為其他在某些編碼某些范圍內(nèi)可能會(huì)出現(xiàn)轉(zhuǎn)換不全,比如latin1->gbk(很特殊的中文),或者編碼長(zhǎng)度改變,比如latin1->utf8,變?yōu)?、3等字節(jié)數(shù)。

下面引用另一篇文章(http://hi.baidu.com/cuttinger/item/f4e79726a60ab450c28d59da)中的一段。

【Latin1是一種很常見的字符集,這種字符集是單字節(jié)編碼,向下兼容ASCII,其編碼范圍是0x00-0xFF,0x00-0x7F之間完全和ASCII一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號(hào)。很明顯,Latin1覆蓋了所有的單字節(jié),因此,可以將任意字符串保存在latin1字符集中,而不用擔(dān)心有內(nèi)容不符合latin1的編碼規(guī)范而被拋棄!猤bk和utf8是多字節(jié)編碼,沒有這種特性。

 mysql使用者經(jīng)常利用Latin1的這種全覆蓋特性,將其它類型的字符串,gbk,utf8,big5等,保存在latin1列中。保存的過程中沒有數(shù)據(jù)丟失,只要原樣取出來,便又是合法的gbk/utf8/big字符串。如果將gbk字符串保存在utf8列中,則gbk字符串中那些不符合utf8編碼格式的內(nèi)容,會(huì)被拋棄,保存的內(nèi)容無法原樣取出,數(shù)據(jù)實(shí)際上遭到了破壞。

 綜上,如果我們看到一個(gè)字段的字符集是latin1的,那么,他保存的可能是任何編碼的字符串;而一個(gè)字段的字符集是utf8或者gbk的,那么他保存的就應(yīng)該是utf8或gbk的——除非數(shù)據(jù)庫的使用者用錯(cuò)了!

我沒有深入學(xué)習(xí)過utf8、gbk編碼的細(xì)節(jié),極可能說的不準(zhǔn)確,只知道簡(jiǎn)單的ASCII編碼(-_-),但是可以了解個(gè)全局情況。從上面來看,latin1的單字節(jié)編碼方式很有用,其他的編碼可以轉(zhuǎn)換為它再轉(zhuǎn)回去而不至于丟失內(nèi)容。所謂單字節(jié)編碼就是挨著一個(gè)個(gè)來,我理解是,比如圣誕節(jié)到了,你要送妹子一箱蘋果,為制造浪漫,商鋪提供兩種包裝方式,一是按個(gè)數(shù)來,即單個(gè)蘋果包裝進(jìn)一個(gè)盒子,來一個(gè)包裝一個(gè),這樣,妹子在拆完所有的盒子后完完整整的可以還原為一個(gè)個(gè)完整的和一箱完好無損的蘋果,二是按重量來,每個(gè)盒子限重2兩、3兩、6兩,這樣在包裝時(shí),若剛好重3兩的當(dāng)然可以完整的放進(jìn)一個(gè)盒子,但是若不夠或者多了,勉不了要切開蘋果,或者再往盒子中添加其他的部分蘋果,這樣的話,妹子再無論怎樣拆開盒子,都會(huì)得到一箱殘缺不堪的蘋果了,因?yàn)槟阍诎凑者@種包裝方式進(jìn)行時(shí),已經(jīng)破壞了單個(gè)蘋果的完整性,現(xiàn)在還原不回來了~我們的字符集編碼轉(zhuǎn)換就是在做這種重新包裝的工作,latin1恰好就像單個(gè)蘋果包裝,而utf8就像第二種方式。

而剛才說的完全匹配的情況是,你去買一箱蘋果,箱子里邊的所有蘋果重量已經(jīng)恰好要么是2兩,要么是3兩或6兩的,這樣再按重量包裝時(shí)當(dāng)然就恰好分配了,得到的仍然是完整的蘋果。

所以說白了,兩種可行的方式是:

1. 所有變量均設(shè)置成latin1(set names latin1;),這樣,即便我們所使用的編輯客戶端編碼多樣(gbk或utf8),最終可以得到正確結(jié)果;

2. 所有的設(shè)置成gbk或者gb2312(國標(biāo)編碼,只用于簡(jiǎn)體中文),采用完全匹配;

3. 針對(duì)中間的轉(zhuǎn)換過程,比如gbk輸入,將character_set_client、character_set_connection視為latin1,character_set_database設(shè)為gb2312,建表時(shí)定字符集為gb2312,character_set_results也可以定為gb2312,當(dāng)然這只是雞肋,本質(zhì)上還是用了latin1,gbk轉(zhuǎn)latin1再轉(zhuǎn)gb2312時(shí)只適用于簡(jiǎn)體。

最后,關(guān)于字符集校對(duì)規(guī)則,只了解一點(diǎn)。在我們?cè)O(shè)置mysql字符集時(shí),mysql會(huì)自動(dòng)給一個(gè)對(duì)應(yīng)的校對(duì)規(guī)則,比如設(shè)置charset為utf8,默認(rèn)的collation就是utf8_general_ci,gb2312字符集對(duì)應(yīng)gb2312_chinese_ci,mysql命令查看所有校對(duì)規(guī)則是show collation,查看某一對(duì)應(yīng)字符集的校對(duì)規(guī)就是show collation like 'utf8%'了。

字符集校對(duì)是一種對(duì)使用當(dāng)前字符集時(shí)采用的排序、對(duì)比方式,即便同一種字符集,在不同的地區(qū)也是不同的對(duì)比方式,所以才有校對(duì)這么一說,比如utf8_general_ci,這個(gè)ci就是case insensitive,即大小寫不敏感,采用它校對(duì)時(shí),查詢某字段值匹配時(shí),大小寫的記錄都會(huì)出現(xiàn),當(dāng)然還有其他的規(guī)則,utf8打印出來一大坨,不細(xì)研究了~

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過審核才能顯示)