MySQL 預設 latin1 (ISO-8859-1 西歐字符集),不支援中文。插入中文時,編碼與存儲字符集不一致,產生 ??? 或亂碼。
客戶端編碼 = 連接字符集 = 表字符集 = 列字符集 = 結果集字符集 = 應用輸出編碼
**任何一環斷裂 → 亂碼**
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4' -- 自動設置連接字符集
skip-character-set-client-handshake -- 強制忽略客戶端請求字符集
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
CREATE DATABASE `my_db`
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
CREATE TABLE `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL,
`content` TEXT
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;
| 語言/驅動 | 連接字串 / 代碼 |
|---|---|
| JDBC | jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf8mb4&zeroDateTimeBehavior=convertToNull |
| PHP PDO | new PDO("mysql:host=host;dbname=db;charset=utf8mb4", $user, $pass) |
| PHP mysqli | $mysqli->set_charset('utf8mb4') |
| Python PyMySQL | charset='utf8mb4' 參數 |
| Go sqlx | parseTime=true&charset=utf8mb4 |
| Node.js mysql2 | charset: 'utf8mb4' |
| 命令行客戶端 | mysql --default-character-set=utf8mb4 -u user -p |
// Web 頁面
// HTTP 響應頭
Content-Type: text/html; charset=UTF-8
// JSON API
Content-Type: application/json; charset=UTF-8
| 特性 | utf8 (MySQL 別名 utf8mb3) | utf8mb4 |
|---|---|---|
| 最大字節 | 3 字節 | 4 字節 |
| 支援 Emoji | ❌ | ✅ |
| 支援生僻字 | ❌ (部分) | ✅ (Unicode 全集) |
| 索引長度限制 | 767 字節 (InnoDB) | 767 字節 (需 innodb_large_prefix=ON 解除 3072) |
結論:全鏈路統一用 utf8mb4,拒絕 utf8
# 1. 修改配置文件 my.cnf (如上)
# 2. 重啟 MySQL
# 3. 轉換庫/表/欄位
ALTER DATABASE `db` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE `table` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 或單欄位
ALTER TABLE `table` MODIFY `col` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 4. 驗證
SELECT CHARSET(column_name), COLLATION(column_name) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='db';
// PHP 連接後立即執行
$pdo->exec("SET NAMES 'utf8mb4'");
// 或 mysqli
$mysqli->query("SET NAMES 'utf8mb4'");
// 或舊版 mysql
mysql_query("SET NAMES 'utf8mb4'", $conn);
原理:SET NAMES 相當於同時設置 character_set_client、character_set_connection、character_set_results 三個會話變量。
// 1. 頁面指令
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
// 2. Filter 統一設置 (web.xml)
EncodingFilter
com.example.EncodingFilter
encoding
UTF-8
EncodingFilter
/*
// 3. Tomcat server.xml Connector
INSERT INTO t VALUES ('中文😀')SELECT HEX(col), CHAR_LENGTH(col), CHARSET(col) FROM tmysqlbinlog -v binlog.000001 | grep 中文中文亂碼不是 MySQL 的錯,是 **全鏈路字符集不一致** 的錯。**統一 utf8mb4、顯式指定、驗證閉環**,一次配置,永久告別亂碼。