中文亂碼/存儲失敗本質是客戶端、連接層、服務端、表、列五層字符集不一致。本文提供 MySQL 5.7/8.0 完整配置鏈路、JDBC 連接串參數、驗證腳本、常見框架設置,實現端到端 utf8mb4 閉環。
| 現象 | 根因 | 核心原因 |
|---|---|---|
插入中文報 Incorrect string value: '\\xXX\\xXX...' | 列字符集不支持該字符 | 列為 latin1/utf8,無法存 4 字節字符 (Emoji、生僻字) |
插入成功但查詢顯示 ??? 或亂碼 | 連接層字符集錯誤 | 客戶端發送 utf8mb4,連接層按 latin1 解碼,寫入錯誤字節 |
| 存儲正常、應用讀取亂碼 | 應用層解碼字符集錯誤 | JDBC 連接串缺 characterEncoding=utf8 |
┌─────────────────────────────────────────────────────────────┐
│ 1. 應用代碼/配置文件 → 指定連接字符集 utf8mb4 │
├─────────────────────────────────────────────────────────────┤
│ 2. 連接器/驅動 → 發送 SET NAMES utf8mb4 │
├─────────────────────────────────────────────────────────────┤
│ 3. MySQL Server 會話變量 → character_set_client/connection/results = utf8mb4 │
├─────────────────────────────────────────────────────────────┤
│ 4. 表默認字符集 → DEFAULT CHARSET=utf8mb4 │
├─────────────────────────────────────────────────────────────┤
│ 5. 列字符集 → CHARSET utf8mb4 (繼承表或顯式) │
└─────────────────────────────────────────────────────────────┘
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init_connect='SET NAMES utf8mb4'
skip-character-set-client-handshake # 強制忽略客戶端聲明,統一用服務端設置
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
關鍵參數:skip-character-set-client-handshake 讓服務端強制統一字符集,防止客戶端錯誤聲明覆蓋。
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
-- 期望輸出:
-- character_set_server=utf8mb4
-- character_set_database=utf8mb4
-- character_set_client=utf8mb4
-- character_set_connection=utf8mb4
-- character_set_results=utf8mb4
-- collation_server=utf8mb4_general_ci
-- 1. 修改庫默認
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
-- 2. 修改表默認 (僅影響後續新建列)
ALTER TABLE tbl_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
-- 3. 修改現有列 (必須指定列定義完整)
ALTER TABLE tbl_name
MODIFY COLUMN col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '註釋';
-- 4. 批量生成遷移腳本
SELECT CONCAT('ALTER TABLE `', TABLE_NAME, '` MODIFY `', COLUMN_NAME, '` ', COLUMN_TYPE,
' CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci',
IF(IS_NULLABLE='NO',' NOT NULL',''), ';')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='your_db' AND CHARACTER_SET_NAME != 'utf8mb4';
| 框架/語言 | 關鍵配置 |
|---|---|
| JDBC (MySQL Connector/J 5.1+) | jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai |
| JDBC 8.0+ (caching_sha2_password) | 同上 + &allowPublicKeyRetrieval=true (非 SSL 環境) |
| Python (PyMySQL / mysql-connector) | charset='utf8mb4' 參數 |
| Go (go-sql-driver/mysql) | charset=utf8mb4,utf8 DSN 參數 |
| Node.js (mysql2) | charset: 'utf8mb4' 配置項 |
| PHP (PDO) | charset=utf8mb4 DSN 參數 |
| C# (MySql.Data) | CharSet=utf8mb4 連接字符串 |
| Spring Boot | spring.datasource.url=jdbc:mysql://...&characterEncoding=utf8mb4 |
| MyBatis | 同 JDBC,無額外配置 |
| Hibernate | hibernate.connection.characterEncoding=utf8mb4 |
utf8 (MySQL 別名 utf8mb3) 僅支持 3 字節,**無法存 Emoji/生僻字**,必須用 utf8mb4。C:\ProgramData\MySQL\MySQL Server X.Y\my.ini,而非安裝目錄。systemctl restart mysqld 或重啟服務。中文亂碼核心在於字符集鏈路斷點。解決三步走:1. 服務端 my.cnf 統一 utf8mb4 + skip-character-set-client-handshake 2. 現有表列遷移至 utf8mb4 3. 所有連接配置顯式指定 utf8mb4。驗證 SHOW VARIABLES LIKE 'character_set%' 五個 client/connection/results/server/database 全為 utf8mb4 即大功告成。