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)顯示的話(huà),如果不想亂碼的話(huà),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è)字符集,就基本可以滿(mǎn)足輸入數(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中的布爾值,怎么存儲(chǔ)false或true
這篇文章主要介紹了MySQL中的布爾值,怎么存儲(chǔ)false或true的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06mysql數(shù)據(jù)庫(kù)實(shí)現(xiàn)超鍵、候選鍵、主鍵與外鍵的使用
數(shù)據(jù)庫(kù)設(shè)計(jì)時(shí),關(guān)鍵字的概念至關(guān)重要,本文就來(lái)介紹一下mysql數(shù)據(jù)庫(kù)實(shí)現(xiàn)超鍵、候選鍵、主鍵與外鍵的使用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-09-09Windows MySQL修改配置文件my.ini不生效問(wèn)題
在Windows Server 2019上修改MySQL 5.6的安裝目錄下my.ini文件后,需要通過(guò)修改注冊(cè)表中的ImagePath值來(lái)確保MySQL讀取新的配置文件,修改時(shí)應(yīng)確保配置文件路徑正確,并且新配置不會(huì)覆蓋原有配置,以保證修改生效2025-01-01關(guān)于mysql數(shù)據(jù)庫(kù)格式化簡(jiǎn)單介紹
本文將介紹關(guān)于mysql數(shù)據(jù)庫(kù)格式化時(shí)需要注意的一些問(wèn)題,需要的朋友可以參考下2012-11-11Mysql掛掉后無(wú)法重啟報(bào)pid文件丟失的解決方法
這篇文章主要介紹了Mysql掛掉后無(wú)法重啟報(bào)pid文件丟失的解決方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09Windows環(huán)境下的MYSQL5.7配置文件定位圖文分析
本文通過(guò)圖文并茂的形式給大家介紹了Windows環(huán)境下的MYSQL5.7配置文件定位 ,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05MySQL數(shù)據(jù)庫(kù)SELECT查詢(xún)表達(dá)式解析
這篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)SELECT查詢(xún)表達(dá)式解析,文中給大家介紹了select_expr 查詢(xún)表達(dá)式書(shū)寫(xiě)方法,需要的朋友可以參考下2018-04-04