日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql set语句_不得不注意!那些容易被忽视的MySQL字符集问题?

發布時間:2025/3/19 数据库 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql set语句_不得不注意!那些容易被忽视的MySQL字符集问题? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

現象

在使用MySQL客戶端書寫SQL語句的時候,我們可以在字符串前邊加_charset_name的符號,其中的charset_name對應著某個具體的字符集,廢話不多說,先寫兩個例子看一下:

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

可以看到第一個查詢結果正常,第二個查詢出現了亂碼。為什么呢?下邊細細道來。

原因

我們知道MySQL是一個C/S架構的軟件,可以有很多客戶端連接到服務器進行交互??蛻舳税l送給服務器的請求以及服務器發送給客戶端的響應本質上都是一個二進制的字節串,每當我們從客戶端發送一個請求到服務器,服務器處理完成之后再把響應返回給客戶端的過程其實發生了很多字符集轉換過程。

  • 首先請求會被MySQL客戶端編碼為字節序列之后通過網絡傳輸到服務器。對于MySQL自帶的客戶端來說,這個編碼過程使用的字符集和我們使用的操作系統的默認字符集是一樣的,類Unix系統的默認字符集就是utf8,Windows系統的默認字符集就是gbk。
  • 服務器收到字節序列請求之后,會認為該字節串是按照character_set_client系統變量編碼的,之后將其從character_set_client轉換到character_set_connection,之后進行更深入的處理。
  • 最后再將響應發送到客戶端的時候,又會按照character_set_results進行編碼。
  • 客戶端收到響應字節串之后,按照本客戶端規定的字符集進行解碼。對于MySQL自帶的客戶端來說,這個解碼過程使用的字符集和我們使用的操作系統的默認字符集是一樣的,類Unix系統的默認字符集就是utf8,Windows系統的默認字符集就是gbk。

總結一下這幾個涉及到的通信字符集系統變量:

系統變量描述character_set_client服務器解碼請求時使用的字符集character_set_connection服務器處理請求時會把請求字符串從character_set_client轉為character_set_connectioncharacter_set_results服務器向客戶端返回數據時使用的字符集

現在我的系統中的這幾個系統變量的值都是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前綴,意味著禁止服務器將后續字節從character_set_client轉換到character_set_connection,而是默認使用_charset_name代表的字符集作為它后續字節的字符集。比方說:

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

我現在使用的是macOS操作系統,所以

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

之后將漢字'鎴'再按照utf8進行編碼,得到的結果就是E98EB4,把它發送到客戶端。

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

擴展

如果在我的機器上我執行SELECT LENGTH(_gbk '我')會得到什么結果呢(LENGTH函數用來統計某個字符串共占用多少字節)?有很多小伙伴不經思考,脫口而出:2!哈哈,我們看一下結果驗證一下:

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

WTH?竟然是3?其實再回想一下我們上邊所說的,因為'我'前邊加了_gbk,所以不會經歷從character_set_client到character_set_connection的轉換過程,而是直接把0xE68891當作是一個采用gbk編碼的字節串。這個字節串中有3個字節,當然結果就返回3了(雖然0x91這個字節在gbk字符集中是無效的,可以看到上邊查詢語句中也給出了Warning)。

思考

如果我現在不使用基于macOS操作系統的客戶端,而采用基于Windows操作系統的客戶端來發送請求,那么下邊的語句的返回結果將會是什么呢:

SELECT LENGTH(_utf8 '我');

總結

以上是生活随笔為你收集整理的mysql set语句_不得不注意!那些容易被忽视的MySQL字符集问题?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。