許多開發者知道在連線後執行 SET NAMES utf8 可解決亂碼,但不清楚其內部機制。本文從字元集變數傳遞路徑角度深度解析。
character_set_client:客戶端發送 SQL 的編碼character_set_connection:Server 端解析 SQL 時的編碼character_set_results:Server 返回結果集的編碼character_set_server:Server 預設編碼(建庫/建表預設)character_set_database:當前資料庫預設編碼character_set_system:系統識別符編碼(固定 utf8)寫入路徑: Client → Connection → Server
讀取路徑: Server → Connection → Results
每個路徑經歷兩次編碼轉換。若中間環節編碼不匹配(如 latin1 ↔ utf8),轉換為不可逆的破壞性操作,導致亂碼或問號。
SET NAMES utf8; -- 等同於執行以下三條: SET character_set_client = utf8; SET character_set_connection = utf8; SET character_set_results = utf8;
執行前後對比(預設 latin1 環境):
-- 執行前 character_set_client | latin1 character_set_connection | latin1 character_set_results | latin1 -- 執行後 character_set_client | utf8 character_set_connection | utf8 character_set_results | utf8
即使 my.cnf 設定 default-character-set=utf8,character_set_client/connection/results 三個會話級變數仍可能為 latin1(視驅動程式實現而定)。SET NAMES 的作用僅限當前連線,重啟或重連後失效。
SET NAMES utf8mb4(支援完整 Unicode,含 Emoji)[mysqld] character-set-server=utf8mb4 + [client] default-character-set=utf8mb4characterEncoding=utf8、PHP PDO MYSQL_ATTR_INIT_COMMAND、Python charset='utf8mb4'CREATE DATABASE ... CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ciSET NAMES 統一了 Client/Connection/Results 三個關鍵環節的編碼,消除轉換鏈路中的編碼不匹配。為了跨環境相容性,每次連線都應顯式執行,即使當前環境看似正常。