SET @str = '李';
SELECT * FROM users WHERE name LIKE CONCAT('%', @str, '%');
-- 結果包含非「李」字的記錄
latin1_swedish_ci / utf8_general_ci 為 不區分大小寫 (CI) 校對規則。latin1,中文雙位元組被拆解為單位元組比對,導致錯誤匹配。LIKE 在 CI 校對下會將漢字內碼視為可轉換字元,產生誤判。-- 查詢層級
SELECT * FROM users WHERE name LIKE BINARY CONCAT('%', @str, '%');
-- 或建表指定
ALTER TABLE users MODIFY name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
原理: _bin 校對逐位元組比較,繞過語言規則。
# 編譯時
cmake -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_unicode_ci ..
# my.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
[client]
default-character-set=utf8mb4
重啟後新建表自動繼承,舊表需 ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4。
SELECT * FROM users WHERE LOCATE(@str, name) > 0;
-- 或
SELECT * FROM users WHERE INSTR(name, @str) > 0;
函數內部逐位元組搜尋,不受校對規則影響。
-- 連線後立即執行
SET NAMES utf8mb4;
-- 或 JDBC URL
jdbc:mysql://host:3306/db?characterEncoding=utf8mb4&connectionCollation=utf8mb4_unicode_ci
| 場景 | 推薦方案 | 備註 |
|---|---|---|
| 新專案 | 方案 2 (utf8mb4 + unicode_ci) | 徹底解決、支援 Emoji |
| 舊專案不可改表 | 方案 1 (LIKE BINARY) 或 3 (LOCATE) | 零風險、效能略降 |
| 僅特定查詢需精確 | 方案 1 (BINARY) | 精準控制 |
| 應用框架統一管理 | 方案 4 (SET NAMES) | 集中配置 |
BINARY / _bin 會導致全表掃描,大表建議加全文索引 (FULLTEXT) 或改用 LOCATE 配合前綴索引。utf8mb4_unicode_520_ci / utf8mb4_0900_ai_ci 提供更準確的 Unicode 排序權重。中文查詢亂碼本質是 字符集與校對規則不匹配,統一全鏈路 utf8mb4 是唯一長久之計。