读写分离架构下备份必须显式连接主库,绕过CI4自动路由;需用Database::connect('master')获取原生连接,或调用mysqldump并指定主库参数,同时配合FLUSH TABLES WITH READ LOCK与binlog定位保障一致性。

读写分离架构下不能直接用 $this->db 做备份操作
CodeIgniter 4 默认的 $this->db 是单例连接,且在读写分离配置中通常被重写为“智能路由”对象(比如根据 SQL 类型自动分发到主库或从库)。但数据备份本质是**全量导出 + 文件写入**,不是普通查询,它需要稳定、独占、可控制的连接,且必须明确指向主库——否则可能从只读从库拉取不一致快照,甚至报错 ERROR 1290 (HY000): The MySQL server is running with the --read-only option。
备份必须显式加载主库连接,而非依赖自动路由
CI4 的读写分离扩展(如自定义 DB 类或第三方包)一般只拦截 query()、get()、insert() 等方法,但不会接管 mysqli_dump 或 mysqldump 调用。所以你得绕过路由逻辑,直连主库:
- 确认主库配置组名(如
$db['master']),并在app/Config/Database.php中已正确定义hostname、username、password和database - 在备份脚本(如命令行
php spark backup:full)中,用\Config\Database::connect('master')获取原始连接资源,而非service('database') - 避免使用
$builder->from()->get()拉表数据——它仍走读写分离逻辑;改用原生mysqli或PDO执行SELECT * FROM table_name并流式写入文件 - 若用
mysqldump外部命令,参数必须显式指定--host、--user、--password和--databases,不能复用 CI4 的连接配置
备份过程中从库延迟会导致一致性风险
即使你成功连上主库,如果备份耗时较长(比如大表 SELECT INTO OUTFILE),而从库同步延迟 >0,那么后续基于备份恢复的环境,与当前主库状态就不一致。这不是 CI4 的问题,而是 MySQL 主从机制本身限制:
- 备份前执行
FLUSH TABLES WITH READ LOCK(需 SUPER 权限),再SHOW MASTER STATUS记录 binlog 位置,解锁后立即开始 dump —— 这能保证逻辑一致性 - CI4 应用层无法自动加全局读锁,该操作必须由 DBA 或独立运维脚本完成,应用只负责调用和写文件
- 不要在备份期间执行
TRUNCATE、DROP或大事务,否则锁等待会拖慢备份,甚至触发超时中断 - 备份文件命名建议包含时间戳 + binlog position,例如
backup_20260806_123456_000001-bin.000042.sql
CI4 的 DatabaseBackup 类不兼容读写分离配置
CI4 自带的 CodeIgniter\Database\MySQLi\Forge 和 CodeIgniter\Database\BaseUtils 不提供完整备份能力;社区常见方案(如 sparks/ci4-backup)默认只用 $db 实例,一旦启用了读写分离,就会随机落到某个从库并失败。真正可用的路径只有两条:
- 自己封装一个
BackupManager类,构造时强制传入ConnectionInterface $masterDb,内部全部用$masterDb->getConnection()->getRawConnection()拿到底层资源 - 完全脱离 CI4 数据库层,用
exec("mysqldump ... > /path/to/backup.sql 2>&1")并捕获返回码,失败时抛出RuntimeException,而不是依赖$this->db->error() - 注意:
exec在生产环境常被禁用,此时必须改用proc_open()+stream_get_contents()安全调用
备份不是“多连几个库就能搞定”的事——它要求精确控制连接目标、规避自动路由、尊重 MySQL 复制约束,并且必须与 DBA 协同操作锁和 binlog。任何试图在 CI4 应用层“透明化”备份的封装,都会在高延迟或大容量场景下暴露一致性缺陷。


















