日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747


不得不注意!那些容易被忽視的MySQL字符集問題?

 

現(xiàn)象

在使用MySQL客戶端書寫SQL語句的時(shí)候,我們可以在字符串前邊加_charset_name的符號(hào),其中的charset_name對(duì)應(yīng)著某個(gè)具體的字符集,廢話不多說,先寫兩個(gè)例子看一下:

mysql> SELECT _utf8'我';
+-----+
| 我 |
+-----+
| 我 |
+-----+
1 row in set (0.04 sec)

mysql> SELECT _gbk'我';
+-----+
| 鎴 |
+-----+
| 鎴 |
+-----+
1 row in set, 1 warning (0.02 sec)

可以看到第一個(gè)查詢結(jié)果正常,第二個(gè)查詢出現(xiàn)了亂碼。為什么呢?下邊細(xì)細(xì)道來。

原因

我們知道MySQL是一個(gè)C/S架構(gòu)的軟件,可以有很多客戶端連接到服務(wù)器進(jìn)行交互。客戶端發(fā)送給服務(wù)器的請(qǐng)求以及服務(wù)器發(fā)送給客戶端的響應(yīng)本質(zhì)上都是一個(gè)二進(jìn)制的字節(jié)串,每當(dāng)我們從客戶端發(fā)送一個(gè)請(qǐng)求到服務(wù)器,服務(wù)器處理完成之后再把響應(yīng)返回給客戶端的過程其實(shí)發(fā)生了很多字符集轉(zhuǎn)換過程。

  • 首先請(qǐng)求會(huì)被MySQL客戶端編碼為字節(jié)序列之后通過網(wǎng)絡(luò)傳輸?shù)椒?wù)器。對(duì)于MySQL自帶的客戶端來說,這個(gè)編碼過程使用的字符集和我們使用的操作系統(tǒng)的默認(rèn)字符集是一樣的,類Unix系統(tǒng)的默認(rèn)字符集就是utf8,windows系統(tǒng)的默認(rèn)字符集就是gbk。
  • 服務(wù)器收到字節(jié)序列請(qǐng)求之后,會(huì)認(rèn)為該字節(jié)串是按照character_set_client系統(tǒng)變量編碼的,之后將其從character_set_client轉(zhuǎn)換到character_set_connection,之后進(jìn)行更深入的處理。
  • 最后再將響應(yīng)發(fā)送到客戶端的時(shí)候,又會(huì)按照character_set_results進(jìn)行編碼。
  • 客戶端收到響應(yīng)字節(jié)串之后,按照本客戶端規(guī)定的字符集進(jìn)行解碼。對(duì)于MySQL自帶的客戶端來說,這個(gè)解碼過程使用的字符集和我們使用的操作系統(tǒng)的默認(rèn)字符集是一樣的,類Unix系統(tǒng)的默認(rèn)字符集就是utf8,Windows系統(tǒng)的默認(rèn)字符集就是gbk。

總結(jié)一下這幾個(gè)涉及到的通信字符集系統(tǒng)變量:

系統(tǒng)變量描述character_set_client服務(wù)器解碼請(qǐng)求時(shí)使用的字符集character_set_connection服務(wù)器處理請(qǐng)求時(shí)會(huì)把請(qǐng)求字符串從character_set_client轉(zhuǎn)為character_set_connectioncharacter_set_results服務(wù)器向客戶端返回?cái)?shù)據(jù)時(shí)使用的字符集

現(xiàn)在我的系統(tǒng)中的這幾個(gè)系統(tǒng)變量的值都是utf8:

mysql> SHOW VARIABLES LIKE 'character_set_client';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| character_set_client | utf8 |
+----------------------+-------+
1 row in set (0.24 sec)

mysql> SHOW VARIABLES LIKE 'character_set_connection';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| character_set_connection | utf8 |
+--------------------------+-------+
1 row in set (0.25 sec)

mysql> SHOW VARIABLES LIKE 'character_set_results';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| character_set_results | utf8 |
+-----------------------+-------+
1 row in set (0.30 sec)

如果我們使用了_charset_name前綴,意味著禁止服務(wù)器將后續(xù)字節(jié)從character_set_client轉(zhuǎn)換到character_set_connection,而是默認(rèn)使用_charset_name代表的字符集作為它后續(xù)字節(jié)的字符集。比方說:

mysql> SELECT _gbk'我';
+-----+
| 鎴 |
+-----+
| 鎴 |
+-----+
1 row in set, 1 warning (0.02 sec)

我現(xiàn)在使用的是macOS操作系統(tǒng),所以

  • 客戶端發(fā)送請(qǐng)求時(shí)會(huì)將字符'我'按照utf8進(jìn)行編碼,也就是:0xE68891。
  • 服務(wù)器收到請(qǐng)求后發(fā)現(xiàn)有前綴_gbk,則不會(huì)將其后邊的字節(jié)0xE68891進(jìn)行從character_set_client到character_set_connection的轉(zhuǎn)換,而是直接把0xE68891認(rèn)為是某個(gè)字符串由gbk編碼后得到的字節(jié)序列。
  • 然后再把上述0xE68891從gbk轉(zhuǎn)換為character_set_results,也就是utf8。0xE688在gbk中代表漢字'鎴',而0x91無法解碼(我們可以看到上述查詢結(jié)果中有1個(gè)warning)。我們緊接著上邊的查詢語句執(zhí)行一下SHOW WARNINGS:
mysql> SHOW WARNINGSG
*************************** 1. row ***************************
 Level: Warning
 Code: 1300
Message: Invalid gbk character string: '91'
1 row in set (0.01 sec)

之后將漢字'鎴'再按照utf8進(jìn)行編碼,得到的結(jié)果就是E98EB4,把它發(fā)送到客戶端。

  • 客戶端收到之后再解碼到屏幕上,解碼也使用utf8字符集,所以就出現(xiàn)了鎴。

擴(kuò)展

如果在我的機(jī)器上我執(zhí)行SELECT LENGTH(_gbk '我')會(huì)得到什么結(jié)果呢(LENGTH函數(shù)用來統(tǒng)計(jì)某個(gè)字符串共占用多少字節(jié))?有很多小伙伴不經(jīng)思考,脫口而出:2!哈哈,我們看一下結(jié)果驗(yàn)證一下:

mysql> SELECT LENGTH(_gbk '我');
+--------------------+
| LENGTH(_gbk '我') |
+--------------------+
| 3 |
+--------------------+
1 row in set, 1 warning (0.01 sec)

WTH?竟然是3?其實(shí)再回想一下我們上邊所說的,因?yàn)?#39;我'前邊加了_gbk,所以不會(huì)經(jīng)歷從character_set_client到character_set_connection的轉(zhuǎn)換過程,而是直接把0xE68891當(dāng)作是一個(gè)采用gbk編碼的字節(jié)串。這個(gè)字節(jié)串中有3個(gè)字節(jié),當(dāng)然結(jié)果就返回3了(雖然0x91這個(gè)字節(jié)在gbk字符集中是無效的,可以看到上邊查詢語句中也給出了Warning)。

思考

如果我現(xiàn)在不使用基于macOS操作系統(tǒng)的客戶端,而采用基于Windows操作系統(tǒng)的客戶端來發(fā)送請(qǐng)求,那么下邊的語句的返回結(jié)果將會(huì)是什么呢:

SELECT LENGTH(_utf8 '我');

分享到:
標(biāo)簽:MySQL
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定