$this->dbutil->backup() 返回 sql 字符串而非文件路径,需手动用 write_file() 写入磁盘;不设 set_time_limit(0) 和内存限制、未处理视图/分区表兼容性、目录不可写或忽略返回值为 false,均会导致“找不到备份文件”。

$this->dbutil->backup() 返回的是 SQL 字符串,不是文件路径,不写入磁盘就等于没备份;还原时 $this->dbutil->restore() 也不自动执行,必须手动触发查询执行。直接调用不设超时、不限内存、不加错误处理,大库十有八九失败或静默丢数据。
为什么 $this->dbutil->backup() 调用后找不到文件?
因为这个函数只生成 SQL 内容,不负责保存——它返回一个字符串,你得自己用 write_file() 或 file_put_contents() 写入磁盘。
- 常见错误:调用后没检查返回值,
$backup是false(比如含视图/分区表时)却继续写文件,结果生成空 SQL - 路径必须可写:
./backups/目录需存在且 Web 用户有写权限,建议用绝对路径避免相对路径歧义 - 文件名别硬编码:
'backup_' . date('Y-m-d_H-i-s') . '.sql'比'my_db_backup.sql'更安全,防止覆盖 - 若启用了
opcache或输出缓冲,可能干扰write_file(),可加ob_end_clean()前置清理
大数据库备份总超时或内存溢出怎么办?
CI 的 backup() 是全量内存加载模式,100MB 以上 SQL 很容易触发 max_execution_time 或 memory_limit 限制。
- 必须前置设置:
set_time_limit(0)和ini_set('memory_limit', '512M')(根据实际数据量上调) - 别依赖默认
'format' => 'txt':它不压缩,导出后体积大、传输慢;改用gzencode()压缩再写入:file_put_contents($gz_path, gzencode($backup)) - MySQL 8.0+ 若禁用
secure_file_priv,不影响backup()生成,但后续若想用LOAD DATA INFILE恢复就得注意路径白名单 - 真要处理超大库(>500MB),别硬扛——拆成单表循环导出,或切到
xtrabackup等外部工具,CI 只做调度入口
$this->dbutil->restore() 为什么执行后没效果?
这个方法只是解析 SQL 字符串并拼成批量查询,不自动执行;它返回的是一个布尔值,不代表数据库已变更。
- 关键点:
$this->dbutil->restore($sql, TRUE)第二个参数必须为TRUE,否则只做语法校验不执行 - 还原前确认目标库已存在且为空(或已清空),
backup()不含CREATE DATABASE,只含CREATE TABLE和INSERT - 若备份含存储过程或函数,MySQL 用户需有
SELECT ROUTINE权限,否则SHOW CREATE PROCEDURE报错导致整个restore()返回false - 还原过程无事务包装,中途出错不会回滚——建议先
mysqldump --single-transaction备份,或在 CI 外部用mysql命令行导入更稳
最易被忽略的点:CI 的 dbutil 完全绕过数据库连接池和事务管理,备份还原全程独占连接;高并发场景下,务必加锁或挪到低峰期执行,否则可能卡住其他请求。











