執行 SET NAMES utf8 前後,三個關鍵會話變量發生變化:
| 變量 | 設置前 | 設置後 | 含義 |
|---|---|---|---|
character_set_client | gbk | utf8 | 客戶端發送 SQL 的編碼 |
character_set_connection | gbk | utf8 | 服務端解析 SQL、比較字符串時的編碼 |
character_set_results | gbk | utf8 | 結果集返回給客戶端的編碼 |
官方文檔:Connection Character Sets and Collations
客戶端應用
│ 發送 SQL (bytes) ──► character_set_client
▼
MySQL Server
│ 解析/執行 ──► character_set_connection
│ 內部操作 (存儲引擎使用 column charset)
│ 結果集編碼轉換 ──► character_set_results
▼
客戶端應用
│ 接收結果 (bytes) ──► 按 character_set_results 解碼
SET NAMES 'utf8' ≡ SET character_set_client = utf8; SET character_set_connection = utf8; SET character_set_results = utf8;
此外,SET NAMES utf8mb4 會同步設置 collation_connection = utf8mb4_general_ci(或默認校對規則)。
CHARSET=gbk,客戶端發送 UTF-8 字節,未執行 SET NAMES utf8,服務端按 latin1 或 gbk 解析 → 存入錯誤字節 → 讀出亂碼。SET NAMES utf8mb4,或 JDBC URL 加 characterEncoding=utf8mb4。character_set_client=utf8 解析 → 字節被二次解讀 → 存入錯誤數據。character_set_results=latin1,客戶端按 UTF-8 解碼 → 亂碼。SET NAMES utf8mb4 同步設置 results。utf8mb4(支持 Emoji,utf8 實為 utf8mb3)。connectionInitSqls: "SET NAMES utf8mb4"。jdbc:mysql://host:3306/db?characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai
SHOW VARIABLES LIKE 'character_set_%'; SHOW VARIABLES LIKE 'collation_%'; SELECT HEX(column) FROM table WHERE ...; -- 查看真實存儲字節
即使字符集一致,校對規則不同也會導致比較、排序、分組異常。例如 utf8mb4_general_ci vs utf8mb4_unicode_ci 對德語 ß、拼音排序規則不同。建議全鏈路統一 utf8mb4_0900_ai_ci(MySQL 8.0 默認,基於 Unicode 9.0,語感排序、不區分重音、大小寫)。
SET NAMES utf8 本質是同步會話層三個字符集變量,確保「客戶端發什麼、服務端懂什麼、返回什麼、客戶端能識別」。徹底解決亂碼,關鍵在於**全鏈路字符集統一、驅動層自動協商、避免應用層干預編碼**。