-- 1. 檢查資料庫/表/欄位字符集
SHOW CREATE DATABASE db_name;
SHOW CREATE TABLE tbl_name;
SHOW FULL COLUMNS FROM tbl_name;
-- 2. 檢查連線字符集變數
SHOW VARIABLES LIKE 'character_set_%';
SHOW VARIABLES LIKE 'collation_%';
-- 3. 關鍵變數應全為 utf8mb4
character_set_client = utf8mb4
character_set_connection = utf8mb4
character_set_results = utf8mb4
character_set_database = utf8mb4
character_set_server = utf8mb4
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
spring:
datasource:
url: jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai
# 關鍵三參數:useUnicode、characterEncoding、serverTimezone
# HikariCP 自動從 URL 讀取,無需額外配置
# Druid 可額外指定
druid:
connectionProperties: useUnicode=true;characterEncoding=utf8mb4
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4' # 針對非超級用戶自動執行
skip-character-set-client-handshake # 強制忽略客戶端字符集宣告,以服務端為準
注意:utf8mb4 支援 Emoji (4 字節),utf8 僅支援 3 字節,**強烈建議全面使用 utf8mb4**。
-- 建庫指定
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 建表指定
CREATE TABLE t (c VARCHAR(100)) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 修改現有表 (會重建表,鎖表時間長)
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 僅修改預設,不轉換現有資料
ALTER TABLE t CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
| 現象 | 典型原因 | 修復重點 |
|---|---|---|
| 中文變 ??? 或 亂碼 | 資料庫/表為 latin1,寫入 utf8 | ALTER TABLE ... CONVERT TO utf8mb4 |
| 一條資料一半正常一半亂碼 | 連線字符集與資料庫不一致 | JDBC URL 加 characterEncoding、my.cnf 統一 |
| Emoji 存入報錯 / 變 ???? | 使用 utf8 (3 字節) 而非 utf8mb4 | 全鏈路升級 utf8mb4 |
| GET 參數亂碼、POST 正常 | Tomcat URIEncoding 缺失 | server.xml 添加 URIEncoding="UTF-8" |
| 終端查詢顯示亂碼 | 終端編碼與 MySQL character_set_results 不符 | 終端設定 UTF-8、或 SET NAMES utf8mb4 |
utf8 而非 utf8mb4 → Emoji 存不進、截斷characterEncoding → 驅動預設 latin1pt-online-schema-change 零停機轉換字符集character_set_client 等變數確保連線一致性# 寫入測試資料
INSERT INTO t (c) VALUES ('測試中文😀Emoji');
# 讀取並檢查十六進制
SELECT c, HEX(c) FROM t;
-- 正確應顯示:E6 B5 8B E8 AF 95 E4 B8 AD E6 96 87 F0 9F 98 80