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

MySQL 主從同步不一致排查實錄:Prepared Statement + GBK 字符集導致 Binlog 異常轉義

     編輯:MySQL 綜合教學

MySQL 主從同步中斷排查:Prepared Statement + GBK 字符集的隱形陷阱

新功能上線後主從同步報錯 Duplicate entry ... for key 'PRIMARY',Binlog 中 INT 類型 ID 被編碼為 ASCII 十六進制(如 0x3636333130393834)。排查發現:應用使用 Prepared Statement + GBK 多字節字符集,導致主從字符集轉換不一致,Binlog 記錄異常。

故障現象

Last_SQL_Error: Error 'Duplicate entry 
'66310984-2014-04-18 00:00:00--122815.sh' for key 'PRIMARY'' 
on query. Default database: 'bill'. Query: 'INSERT INTO `BOND3311`...
VALUES(0x373236313333373339, 0x3636333130393834, ...)  -- ID 被編碼為十六進制

排查路徑

  1. 主庫數據寫入正常 → 排除應用層寫入邏輯
  2. 對比主從:character_set_server、collation_server、表字符集、SQL_MODE、MySQL 版本 → 全一致
  3. 搜索引擎定位關鍵詞:Prepared Statement GBK binlog hex

根因分析

觸發條件雙重滿足時必現:

  • 應用使用 Prepared Statement(預編譯語句)
  • 連接/表字符集為 多字節字符集(GBK/UTF8MB4)

MySQL 在 Prepared Statement 參數綁定階段,對多字節字符集的參數進行轉義時,會將二進制數據以十六進制形式寫入 Binlog。從庫重放時若字符集上下文不一致,導致解析偏移,主鍵衝突。

解決方案

# 1. 停止同步
STOP SLAVE;

# 2. 修改 Binlog 格式為 ROW(避免語句級轉義問題)
SET GLOBAL binlog_format=ROW;  -- 或配置文件永久生效

# 3. 重新同步基線數據
-- 主庫:mysqldump --master-data=2 --single-transaction db > base.sql
-- 從庫:mysql db < base.sql

# 4. 重置從庫位點並啟動
RESET SLAVE;
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.xxxxxx', MASTER_LOG_POS=xxx;
START SLAVE;

長期預防

  1. 統一字符集為 utf8mb4,棄用 GBK
  2. 框架層避免在多字節字符集下大量使用 Prepared Statement,或顯式指定字符集
  3. 監控 Seconds_Behind_Master 與 Last_SQL_Error,設置告警

參考博客:Prepared Statement + GBK 導致 Binlog 異常深度解析

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