JDBC 寫入 MySQL 出現問號(???),本質是 客戶端編碼 → 連接層轉換 → 伺服器儲存 → 表/列定義 → 讀取回傳 任一環節字元集不匹配導致的資訊損失。UTF-8 為例,若某環節為 latin1/gbk,多位元組字符會被截斷或錯誤映射。
-- 1. 查看當前字元集設置
SHOW VARIABLES LIKE '%char%';
SHOW VARIABLES LIKE '%collation%';
-- 關鍵變數預期值(UTF-8 方案)
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci -- 或 utf8mb4_unicode_ci
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init_connect='SET NAMES utf8mb4' -- 針對非超級用戶自動設置
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
關鍵點:utf8mb4 支援 4 位元組字符,utf8 實為 utf8mb3 僅支援 BMP 平面,生產環境強制 utf8mb4。
-- 檢查資料庫字元集
SHOW CREATE DATABASE db_name;
-- 檢查表字元集
SHOW CREATE TABLE table_name;
-- 檢查列字元集
SHOW FULL COLUMNS FROM table_name;
-- 資料庫級
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
-- 表級(僅影響新建列)
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 列級精確修改
ALTER TABLE table_name MODIFY COLUMN col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
避坑:CONVERT TO 會重建表並轉換現有數據,大表請用 pt-online-schema-change 或維護窗口操作。
jdbc:mysql://host:3306/db_name?
characterEncoding=utf8mb4&
useUnicode=true&
connectionCollation=utf8mb4_general_ci&
serverTimezone=Asia/Shanghai&
useSSL=false&
allowPublicKeyRetrieval=true
characterEncoding 指定客戶端編碼,驅動會發送 SET NAMESjdbc:mysql://host:3306/db_name?
useUnicode=true&
characterEncoding=utf8&
connectionCollation=utf8_general_ci
⚠️ 5.1.x 不支援 utf8mb4,需升級驅動或接受 Emoji 無法儲存。
spring.datasource.url=jdbc:mysql://host:3306/db?characterEncoding=utf8mb4&useUnicode=true&serverTimezone=Asia/Shanghai
spring.datasource.hikari.connection-init-sql=SET NAMES utf8mb4 COLLATE utf8mb4_general_ci
druid.connectionProperties=useUnicode=true;characterEncoding=utf8mb4
# 或
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci
SELECT HEX(col), col FROM table WHERE id=? 查看實際儲存的十六進位SHOW SESSION VARIABLES LIKE '%char%'; 在應用連接中執行p6spy 攔截實際發送的 SQL| 場景 | 症狀 | 根因 | 解決 |
|---|---|---|---|
| Emoji 儲存失敗 | 報錯 Incorrect string value | 列/表為 utf8 (mb3) | ALTER TABLE ... CONVERT TO utf8mb4 |
| 讀取顯示亂碼 | 中文變 或 ??? | 讀取時字元集不匹配 | 連接字串加 characterEncoding、檢查頁面/控制台編碼 |
| Druid/Hikari 連接池 | 重啟後正常,運行一段時間亂碼 | 連接復用未重置字元集 | 配置 connectionInitSqls 設置 SET NAMES |
| 舊系統遷移 | 歷史數據已為 latin1 儲存中文 | 雙重編碼 latin1→utf8 | 導出→修正編碼→導入,或 CONVERT TO 配合 BINARY 過渡 |
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci 保證每次獲取連接重置JDBC 中文亂碼看似瑣碎,實則考驗對字元集全鏈路的掌控力。遵循「utf8mb4 全棧統一、驅動版本跟進、連接池初始化 SQL 兜底」三大原則,配合系統化排查流程,即可徹底根治。記住:預防勝於治療,新專案第一天就鎖定 utf8mb4。