主库真实 binlog_format 以会话级 SELECT @@binlog_format 为准,非 SHOW VARIABLES;STATEMENT 模式下含 UUID()/NOW()/RAND() 的语句会导致主从不一致,切 ROW 前须确保从库追平且清空含 STATEMENT 事件的 binlog。

确认主库真实 binlog_format 值
SHOW VARIABLES LIKE 'binlog_format' 返回的是 GLOBAL 级别配置,但实际写入日志的是会话级值——旧连接不会自动更新。错误常源于此:主库显示 STATEMENT,却在 binlog 里写入 Write_rows 事件。
必须用业务连接执行:SELECT @@binlog_format;。如果结果是 ROW 而配置文件写的是 STATEMENT,说明有人执行过 SET GLOBAL binlog_format = 'ROW',但未重启或未刷新连接。
- 查残留连接:
SHOW PROCESSLIST;,重点关注User列为应用账号、Command为Sleep的行 - Druid 连接池需设
removeAbandonedOnBorrow=true并调大removeAbandonedTimeout - HikariCP 必须配
connection-test-query=SELECT 1,否则健康检查不触发格式重协商
识别非确定性语句是否已污染 binlog
STATEMENT 模式下,含 UUID()、NOW()、RAND() 的语句在从库执行结果可能不同;一旦切换到 ROW,这些语句本身不报错,但若之前已写入 STATEMENT 日志且从库未同步完,后续切 ROW 后的事件就可能因数据不一致而触发 Error_code: 1032。
开启慢日志后查历史痕迹:SELECT * FROM mysql.slow_log WHERE sql_text REGEXP '(UUID|NOW|SYSDATE|RAND)';
- 若返回大量记录,说明主库长期运行在 STATEMENT 下且存在风险语句
- 这类语句在 ROW 模式下无害,但切换前必须确保从库已追平——否则缺失行直接导致同步中断
- 不要仅靠
Seconds_Behind_Master = 0判断追平,还要比对Exec_Master_Log_Pos和Read_Master_Log_Pos
GTID 模式下混用格式会直接拒绝启动
MySQL 5.7+ 默认启用 GTID,此时 STATEMENT 和 ROW 事务不能共存于同一 binlog 文件。主库若混写(比如老连接写 STATEMENT、新连接写 ROW),从库 IO 线程一启动就报:Got fatal error 1236 或 Cannot replicate because the master's binary log format is not compatible with GTID replication。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
修复路径是硬性的:
- 先关 GTID:
SET GLOBAL gtid_mode = OFF;(需两阶段:先OFF_PERMISSIVE,再OFF) - 确认
SELECT @@gtid_mode;返回OFF后,再改binlog_format - 切回 GTID 前,必须
PURGE BINARY LOGS BEFORE ...清掉所有含 STATEMENT 事件的旧 binlog
从库报 1032 错误时别跳过,先补缺失行
Error_code: 1032 表明从库执行 UPDATE_ROWS 或 DELETE_ROWS 时找不到目标行——本质是主从数据不一致,不是日志格式问题本身。ROW 模式只是把“不一致”暴露得更早、更确定。
从 Last_Error 提取关键信息:Can't find record in 't_user' → 查该表主键 → 在主库执行:SELECT * FROM t_user WHERE id = 12345;
- 拿到完整行后,在从库手动
INSERT(注意默认值、时间戳、触发器逻辑) - 避免用
sql_slave_skip_counter,它掩盖问题,下次同类型变更还会失败 - 批量缺失时,用
pt-table-checksum全量校验 +pt-table-sync修复,比重建从库快且可控
最易被忽略的一点:应用连接池不会自动感知 binlog_format 变更,哪怕你改了配置、甚至重启了 mysqld,只要连接没重建,它就还在用旧格式写日志。










