MySQL字符集中文亂碼解析
問(wèn)題描述
假設(shè)有三個(gè)表test_gbk,test_utf8,test_latin1,創(chuàng)建的時(shí)候字符集分別為gbk,utf8,latin1。表結(jié)構(gòu)為
| Field | Type | Null | Key | Default | Extra |
|---|---|---|---|---|---|
| name | varchar(512) | YES | NULL |
"中"字的gbk十六進(jìn)制表示為:0xd6 d0;utf8 16進(jìn)制表示為:0xe4 b8 ad
問(wèn)題1
執(zhí)行下列語(yǔ)句:
set names 'latin1'; insert into test_latin1 values( '中'); //此處'中'為gbk格式 select name from test_latin1;
結(jié)果是亂碼,還是正常顯示?
問(wèn)題2
執(zhí)行下列語(yǔ)句:
set names 'gbk'; insert into test_latin1 values( '中'); //此處'中'為gbk格式 select name from test_latin1;
結(jié)果是亂碼,還是正常顯示?
問(wèn)題3
執(zhí)行下列語(yǔ)句:
set names 'latin1'; insert into test_utf8 values( '中'); //此處'中'為gbk格式 select name from test_utf8;
結(jié)果是亂碼,還是正常顯示?
原理篇
字符集介紹
為了解釋上述問(wèn)題,首先要了解字符集為何物。字符集也叫字符編碼,就是將字符集合一一映射成一個(gè)數(shù)。以下簡(jiǎn)單介紹一下幾種字符集:
基礎(chǔ)ASCII編碼:
0x00-0x7F表示所有的大寫(xiě)和小寫(xiě)字母,數(shù)字0 到9、標(biāo)點(diǎn)符號(hào), 以及在美式英語(yǔ)中使用的特殊控制字符。
latin1編碼:
單字節(jié)編碼,編碼范圍是0x00-0xFF,0x00-0x7F,和ASCII保持一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號(hào)。
gbk編碼:
使用一字節(jié)和雙字節(jié)編碼,0x00–0x7F范圍內(nèi)是一位,和ASCII保持一致。雙字節(jié)的第一字節(jié)范圍是0x81-0xFE(不含0x80和0xFF)。
utf8編碼:
使用一至四字節(jié)編碼,0x00–0x7F范圍內(nèi)是一位,和ASCII保持一致。其它字符用二至四個(gè)字節(jié)變長(zhǎng)表示。
字符集編碼轉(zhuǎn)換舉例:
0xB1(latin-1) ->'±'-> 0xC2 B1 (utf8)
兩個(gè)重要的點(diǎn)
0x00-0x7F區(qū)間,上述字符集是一致的,也就是說(shuō)英文字符無(wú)需轉(zhuǎn)碼。不同編碼,字符集合不完全一樣,存在某字符集的字符無(wú)法映射到另外一個(gè)字符集。
比如gbk編碼中的中文字符,轉(zhuǎn)成latin-1編碼時(shí),就找不到對(duì)應(yīng)的二進(jìn)制編碼。MySQL做字符集轉(zhuǎn)換的時(shí)候,gbk中文字符->latin-1,很多就轉(zhuǎn)成'?'號(hào)(0x3f),這種大集合轉(zhuǎn)成小集合,基本是不可逆的。
MySQL執(zhí)行過(guò)程
對(duì)一個(gè)MySQL的執(zhí)行過(guò)程,字符集轉(zhuǎn)換,一般涉及到一下三個(gè)步驟:
收到請(qǐng)求,將請(qǐng)求數(shù)據(jù)從
character_set_client->character_set_connection。內(nèi)部操作,將數(shù)據(jù)從
character_set_connection-> 表創(chuàng)建的字符集。結(jié)果輸出,將數(shù)據(jù)從表創(chuàng)建的字符集 ->
character_set_results。
當(dāng)執(zhí)行set names "charset"; 相當(dāng)于把character_set_client, character_set_connection,character_set_results 統(tǒng)一設(shè)置為"charset"。
終端顯示字符集
此外如果你用securecrt終端來(lái)顯示的話,如果不想亂碼的話,appearance->character encoding也需要設(shè)置成正確的字符集。
問(wèn)題詳解
問(wèn)題1
執(zhí)行下列語(yǔ)句:
set names 'latin1'; insert into test_latin1 values( '中'); //此處'中'為gbk格式 select name from test_latin1;
結(jié)果是亂碼,還是正常顯示?
答:結(jié)果是正常顯示。
執(zhí)行流程如下:
set names 'latin1';相當(dāng)于把character_set_client,character_set_connection,character_set_results統(tǒng)一設(shè)置為'latin1'。Character_set_client告訴MySQL Server,傳入的是一個(gè)latin1編碼的,也就是單字節(jié)流,'中'這個(gè)輸入,其實(shí)當(dāng)作了0xD6 D0傳入。因?yàn)?code>character_set_client ->
character_set_connection->table charset->character_set_results為latin1->latin1->latin1->latin1, 編碼完全一致,數(shù)據(jù)沒(méi)有做任何轉(zhuǎn)換,所以輸入是0xD6 D0,最后的輸出也還原為0xD6 D0。如果你的securecrt的顯示字符集設(shè)置為
gbk,那么最后的輸出0xD6 D0就會(huì)顯示成'中'。
問(wèn)題2
執(zhí)行下列語(yǔ)句:
set names 'gbk'; insert into test_latin1 values( '中'); //此處'中'為gbk格式 select name from test_latin1;
結(jié)果是亂碼,還是正常顯示?
答:結(jié)果是亂碼。
執(zhí)行流程如下:
set names 'gbk';相當(dāng)于把character_set_client,character_set_connection,character_set_results統(tǒng)一設(shè)置為'gbk'。Character_set_client告訴MySQL Server,傳入的是一個(gè)gbk編碼的,'中'這個(gè)輸入,當(dāng)作了0xD6 D0傳入。因?yàn)?code>character_set_client ->
character_set_connection->table charset->character_set_results為gbk->gbk->latin1->gbk, 其中gbk->latin1的時(shí)候,因?yàn)?#39;中'這個(gè)字符在latin1字符集里找不到,就會(huì)轉(zhuǎn)換成'?'號(hào)(0x3F),然后latin1->gbk,'?'號(hào)在gbk字符集里面也是0x3F,最后輸出就是0x3F,即'?'號(hào)。
問(wèn)題3
執(zhí)行下列語(yǔ)句:
set names 'latin1'; insert into test_utf8 values( '中'); //此處'中'為gbk格式 select name from test_utf8;
結(jié)果是亂碼,還是正常顯示?
答:正常顯示。
執(zhí)行流程如下:
set names 'latin1';相當(dāng)于把character_set_client,character_set_connection,character_set_results統(tǒng)一設(shè)置為'latin1'。Character_set_client告訴MySQL Server,傳入的是一個(gè)latin1編碼的,'中'這個(gè)輸入,當(dāng)作了0xD6 D0傳入。因?yàn)?code>character_set_client ->
character_set_connection->table charset->character_set_results為latin1->latin1->utf8->latin1, 其中latin1->utf8的時(shí)候,輸入'中' (0xD6 D0)會(huì)當(dāng)作兩個(gè)字符進(jìn)行utf8轉(zhuǎn)換,轉(zhuǎn)換為0xC3 96 C3 90,然后utf8->latin1的時(shí)候,會(huì)把0xC3 96轉(zhuǎn)換成0xD6,0xC3 90轉(zhuǎn)成0x D0,最后輸出0xD6 D0。負(fù)負(fù)得正,之所以數(shù)據(jù)沒(méi)有失真的原因是因?yàn)樾〖贤蠹限D(zhuǎn),再轉(zhuǎn)回來(lái),操作可逆。如果你的securecrt的顯示字符集設(shè)置為gbk,那么最后的輸出
0xD6 D0就會(huì)顯示成'中'。
終極解決方案
從上面的問(wèn)題執(zhí)行流程來(lái)看,有沒(méi)有終極解決方案呢?其實(shí)很簡(jiǎn)單,表創(chuàng)建的字符集和set names都設(shè)置成同一個(gè)字符集,就基本可以滿足輸入數(shù)據(jù)不會(huì)在轉(zhuǎn)換過(guò)程中失真,也就是說(shuō)輸入是什么,輸出就是什么。建議有中文的都設(shè)置成utf8字符集,一勞永逸。
以上就是MySQL字符集中文亂碼解析的詳細(xì)內(nèi)容,更多關(guān)于MySQL字符集中文亂碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MySQL 8.0 Online DDL快速加列的相關(guān)總結(jié)
在實(shí)際的MySQL運(yùn)維過(guò)程中,我們經(jīng)常會(huì)遇到業(yè)務(wù)需要給某張表添加字段的情況,本文將介紹幾種加字段的方法,感興趣的朋友可以參考下2021-06-06
mysql中關(guān)于between和in的區(qū)別
這篇文章主要介紹了mysql中關(guān)于between和in的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
MySQL9.0.1安裝教程的實(shí)現(xiàn)示例
本文主要介紹了MySQL軟件的下載、解壓、環(huán)境變量配置、初始化及啟動(dòng)、登錄與密碼設(shè)置等步驟,詳細(xì)說(shuō)明了每一步的操作方法,感興趣的可以了解一下2024-10-10
Windows系統(tǒng)下MySQL ODBC驅(qū)動(dòng)安裝與配置詳細(xì)步驟
本文介紹Windows系統(tǒng)下MySQL ODBC驅(qū)動(dòng)的安裝與配置步驟,涵蓋系統(tǒng)架構(gòu)確認(rèn)、驅(qū)動(dòng)下載選擇、DSN配置、ANSI/Unicode驅(qū)動(dòng)區(qū)別及常見(jiàn)問(wèn)題解決方案,同時(shí)提供自動(dòng)化部署腳本,幫助用戶解決驅(qū)動(dòng)未顯示、位數(shù)沖突、連接失敗等典型問(wèn)題,感興趣的朋友一起看看吧2025-06-06
MySQL中大數(shù)據(jù)表增加字段的實(shí)現(xiàn)思路
最近遇到的一個(gè)問(wèn)題,需要在一張將近1000萬(wàn)數(shù)據(jù)量的表中添加加一個(gè)字段,但是直接添加會(huì)導(dǎo)致mysql 奔潰,所以需要利用其他的方法進(jìn)行添加,這篇文章主要給大家介紹了MySQL中大數(shù)據(jù)表增加字段的實(shí)現(xiàn)思路,需要的朋友可以參考借鑒。2017-01-01

