首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

一條詭異的 INSERT 報錯:CHAR() 函數導致的字符集隱性轉換陷阱

     編輯:MySQL 綜合教學

一條詭異的 INSERT 報錯:CHAR() 函數導致的字符集隱性轉換陷阱

同事反饋一條簡單的 INSERT 報錯:

Incorrect string value: '\xA1;offl...' for column 'biz_info' at row 1

經過半天排查,根因竟是 CHAR() 函數引發的 二進制字串 → 字符集轉換鏈路錯位。本文完整復現、分析、給出兩種修復方案。

環境與復現

-- 連線字符集:UTF8
-- 表字符集:GBK
CREATE TABLE ggg (
  id INT,
  c VARCHAR(100)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

-- 觸發報錯
INSERT INTO ggg VALUES (
  1,
  CONCAT('cardName:校園網', CHAR(59), 'offlineCardType:campus')
);

CHAR(59) 返回 ; (分號),但類型是 binary 字串。

錯誤鏈路深度解析

  1. CONCAT 參數中混入 binary 類型 → 整個結果被隱性轉為 binary。
  2. 原 UTF8 字串 'cardName:校園網' (9 字節) 被視為 18 字節二進制資料。
  3. 寫入 GBK 表時,MySQL 嘗試 binary → GBK 轉換:
    UTF8 編碼 E6 A0 A1 E5 9B AD E5 8D A1 按 GBK 雙字節切分 → E6A0 A1E5 9BAD E58D A1 → 前 4 字節成亂碼 鏍′洯缃,遇 A1 無法組成合法 GBK 字符 → 報錯。

為何兩種修改就正常?

修改原因
CHAR(59) → ';'字面量 ';' 類型為連線字符集 (UTF8),CONCAT 全程 UTF8 → GBK 直接轉換,正常。
連線字符集改 GBKCHAR(59) 返回 GBK binary → CONCAT 結果 GBK binary → 寫入 GBK 表無轉換,正常。

兩種修復方案 (擇一)

-- 方案 1:指定 CHAR() 返回字符集 (MySQL 5.7+)
INSERT INTO ggg VALUES (
  1,
  CONCAT('cardName:校園網', CHAR(59 USING utf8mb4), 'offlineCardType:campus')
);

-- 方案 2:統一連線與表字符集 (推薦,治本)
-- 應用層連線字符集 = 表字符集 = utf8mb4
-- 或在 my.cnf 強制
[client]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

避坑清單

  • 慎用 CHAR()、HEX()、UNHEX() 等返回 binary 的函數參與字串拼接。
  • 統一字符集鏈路:應用連線、表、欄、資料庫全統一 utf8mb4,杜絕隱性轉換。
  • 參數化查詢:用 ? 佔位符傳參,驅動程式自動處理編碼,避免手工拼接 SQL。
  • 開啟嚴格模式:sql_mode=STRICT_TRANS_TABLES,讓截斷/轉換錯誤直接報錯而非靜默截斷。

結語:字符集問題 90% 來自「連線 ≠ 表」或「函數返回類型不預期」。建立「全鏈路 utf8mb4」標準,配合參數化查詢與嚴格模式,可徹底杜絕此類詭異 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved