MySQL 與 Java 應用交互時,字符集轉換發生在「JDBC 驅動」層。歷史上存在兩種主流解決路徑,且受驅動版本強影響。本文徹底梳理原理、配置差異、版本陷阱與最佳實踐。
jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=UTF-8
characterEncoding 編碼為字節流發送給 MySQL;讀取時按同編碼解碼為 String。default-character-set (服務端字符集統一)# my.cnf / my.ini [mysqld] 區段
[mysqld]
default-character-set=utf8mb4
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# [client] 區段 (可選,影響 mysql 命令行客戶端)
[client]
default-character-set=utf8mb4
SET NAMES utf8mb4,雙方協商一致,**無需客戶端顯式轉碼**。utf8mb4 (完整 Unicode 包含 Emoji)。utf8mb4,會拋出 StringIndexOutOfBoundsException: String index out of range: 40 (內部解析字符集名稱長度硬編碼 Bug)。| 驅動版本 | 推薦方案 | URL 配置示例 | 備註 |
|---|---|---|---|
| 3.0.11 (舊穩定版) | 方案一 (URL 參數) | ?useUnicode=true&characterEncoding=UTF-8 |
不支持 utf8mb4,僅支持 utf8 (BMP)。DBCP 下參數可能失效。 |
| 3.1.x / 5.0.x | 方案二 (服務端 utf8mb4) 首選 | 無需額外參數 (或 ?characterEncoding=utf8mb4 顯式) |
建議升級至 5.1+。 |
| 5.1.49+ (長期支持) | 方案二首選,方案一兼容 | ?characterEncoding=utf8mb4&useSSL=false |
自動檢測服務端 charset。useSSL=false 開發環境必加。 |
| 8.0.28+ (當前主流) | 方案二首選 (默認 utf8mb4) | ?characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true |
默認字符集即 utf8mb4。必加 serverTimezone 避免時區錯誤。 |
若使用 Commons DBCP、Tomcat JDBC Pool、HikariCP 等,URL 參數解析可能不完整。標準做法:使用 connectionProperties 或 dataSourceProperties 顯式設置屬性。
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/your_db"); // 基礎 URL 無參數
config.setUsername("user");
config.setPassword("pwd");
// 關鍵:通過 dataSourceProperties 傳遞驅動屬性
config.addDataSourceProperty("characterEncoding", "utf8mb4");
config.addDataSourceProperty("useUnicode", "true");
config.addDataSourceProperty("useSSL", "false");
config.addDataSourceProperty("serverTimezone", "Asia/Shanghai");
config.addDataSourceProperty("allowPublicKeyRetrieval", "true");
HikariDataSource ds = new HikariDataSource(config);
<Resource name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/your_db"
username="user"
password="pwd"
connectionProperties="characterEncoding=utf8mb4;useUnicode=true;useSSL=false;serverTimezone=Asia/Shanghai"
/>
-- 連接後執行,確認關鍵變量
SHOW VARIABLES LIKE 'character_set_%';
SHOW VARIABLES LIKE 'collation_%';
-- 期望輸出 (方案二 utf8mb4)
character_set_client utf8mb4
character_set_connection utf8mb4
character_set_results utf8mb4
character_set_server utf8mb4
collation_connection utf8mb4_unicode_ci
collation_server utf8mb4_unicode_ci
my.cnf [mysqld] 設置 default-character-set=utf8mb4,重啟 MySQL。**這是根治之道**。connectionProperties 顯式傳遞 characterEncoding=utf8mb4。ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 確保存儲層一致。<%@ page contentType="text/html;charset=UTF-8" %> / <meta charset="UTF-8">。遵循以上法則,徹底告別「????」、「」、「錯位亂碼」等 MySQL 中文噩夢。