tp5.1本身不提供增量备份能力,必须依赖mysql的binlog(推荐row格式)或应用层触发器;前者由mysql自动生成变更日志,tp5.1仅负责调用mysqlbinlog解析与调度,后者需手动为每张表创建触发器写审计日志,但存在性能损耗、ddl捕获缺失及维护成本高等严重缺陷。

TP5.1 本身不提供数据库增量备份能力,它只是 PHP 框架,不能替代 MySQL 的 binlog 或触发器机制;所谓“TP5.1 实现增量备份”,实际是用 TP5.1 写调度脚本或监听逻辑,底层仍必须依赖 MySQL 的 binlog 或应用层触发器 —— 两者不是并列方案,而是适用场景完全不同的技术路径。
为什么不能在 TP5.1 里靠 Model 或 Db 类做增量备份
ThinkPHP 5.1 的 Db 和 Model 是运行时查询/写入接口,不记录历史变更,也不感知事务边界。你无法靠它自动捕获“哪几行被改了、什么时候改的、改前值是什么”。即使加日志中间件,也只能记录请求维度操作(比如“用户A调了/user/update接口”),不是数据维度变更(比如“user 表 id=123 的 email 字段从 a@b.com 变成 c@d.com”)。
常见错误现象:
- 用
Db::listen()记录 SQL,但只拿到执行语句,没有前后镜像,无法还原误操作 - 在控制器里手动写日志,漏掉定时任务、命令行脚本、直接 SQL 执行等非 HTTP 入口变更
- 把
create_time/update_time当增量依据,但删库、清表、批量更新会彻底丢失上下文
Binlog 方案:必须开启且验证 ROW 格式
这是生产环境唯一推荐的增量数据捕获方式,TP5.1 只需调用系统命令或封装 mysqlbinlog 解析逻辑,不参与日志生成。
关键检查项(登录 MySQL 执行):
-
SHOW VARIABLES LIKE 'log_bin';→ 必须返回ON,否则整个流程无效 -
SHOW VARIABLES LIKE 'binlog_format';→ 必须是ROW,STATEMENT在NOW()、UUID()、自增主键场景下无法还原原状 -
SHOW VARIABLES LIKE 'server_id';→ 不能为0,且集群内必须唯一
TP5.1 可做的配合动作:
- 在全量备份后,用
shell_exec("mysqldump --single-transaction --master-data=2 ...")并解析输出中的MASTER_LOG_FILE和MASTER_LOG_POS - 用
shell_exec("mysqlbinlog --base64-output=DECODE-ROWS -v --start-position=...")截取增量 SQL,保存为文件供后续重放 - 注意字符集:重放时若报错
Unknown character set: 'utf8mb4',需在mysql命令中显式加--default-character-set=utf8mb4
触发器方案:仅限小表、低频、无分布式场景
在 MySQL 表上建触发器,把变更写入一张 audit_log 表,TP5.1 读这张表做归档。看似可控,但问题极多:
- 每张业务表都要手动加
INSERT/UPDATE/DELETE三套触发器,维护成本爆炸 - 触发器阻塞主事务,高并发下
UPDATE响应延迟明显升高 - 无法捕获
DROP TABLE、TRUNCATE、ALTER等 DDL,而这些恰恰是灾备中最要命的操作 - TP5.1 若用事务批量写入日志表,一旦失败,主业务和日志不同步,链路断裂
真正适合触发器的场景极少:比如只监控某张核心配置表的字段变更,且该表每天最多几十次写入。
恢复时最容易被忽略的顺序与一致性
无论用哪种方式捕获增量,恢复阶段都必须严格按“全量 → 增量 1 → 增量 2 → …”顺序重放,且所有增量必须覆盖到同一时间点。TP5.1 脚本如果并发拉取多个 binlog 文件并异步处理,极易导致事务乱序 —— 比如事务 A 在 .000012 中提交,事务 B 在 .000013 中提交,但脚本先解析了 .000013 再解析 .000012,B 就会因依赖未就绪而失败。
更隐蔽的问题是 GTID:MySQL 5.7+ 默认启用 GTID,若备份时没关 --set-gtid-purged=OFF,恢复时可能报 The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1 错误,必须提前确认全备文件里是否含 SET @@GLOBAL.GTID_PURGED 语句,并匹配目标实例的 GTID 状态。











