InnoDB 在 READ COMMITTED 或 READ UNCOMMITTED 隔離級別下,必須使用 ROW 或 MIXED 格式的 Binlog,否則執行寫入語句報錯 ERROR 1665 (HY000)。本文解析衝突機制、給出無需重啟的動態修復方案。
ERROR 1665 (HY000): Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
READ COMMITTED 隔離級別下,InnoDB 使用 **Next-Key Lock 退化為 Record Lock**,同一語句多次執行可能看到不同快照(Phantom Read)。STATEMENT 格式 Binlog 記錄 SQL 文本,主從重放時若快照不同會導致數據不一致。READ COMMITTED 時 Binlog 格式為 ROW 或 MIXED。SET GLOBAL binlog_format = 'MIXED'; -- 或 SET GLOBAL binlog_format = 'ROW';
MIXED:MySQL 自動判斷,安全語句用 STATEMENT,不安全(如 UUID、NOW()、UDF、READ COMMITTED 下的 InnoDB)自動切 ROW,兼顧性能與安全,**推薦生產默認值**。# /etc/my.cnf [mysqld] binlog_format = MIXED # 重啟後生效
| 隔離級別 | 允許的 Binlog 格式 | 推薦 |
|---|---|---|
| REPEATABLE READ (默認) | STATEMENT / ROW / MIXED | MIXED |
| READ COMMITTED | ROW / MIXED | ROW 或 MIXED |
| READ UNCOMMITTED | ROW / MIXED | ROW |
| SERIALIZABLE | STATEMENT / ROW / MIXED | MIXED |
binlog_format 為 ROW 會顯著增加 Binlog 體積(全行映像),需配合 expire_logs_days、max_binlog_size 盤容量規劃。STATEMENT 格式(如異構同步工具解析),只能升級隔離級別至 REPEATABLE READ,但會增加鎖爭用,需壓測評估。SESSION 級別也可設:SET SESSION binlog_format = 'ROW'; 供特定遷移任務臨時使用。核心原則:**隔離級別與 Binlog 格式必須匹配**,MIXED 是 99% 場景的「銀彈」。