如何用PHP将MySQL数据库定期备份至另一数据库?
当然可以用PHP实现跨数据库的定期备份!如果之前导出SQL文件的方式不符合需求,直接把源数据库的数据同步到目标数据库会是更贴合的方案。我之前做过类似的需求,下面给你详细的实现思路和代码示例:
核心实现逻辑
要完成这个备份,核心是同时连接源数据库和目标数据库,然后分两步同步:
- 同步表结构(如果目标库还没有对应表,或者需要更新结构的话)
- 同步表数据(支持全量覆盖或增量更新,根据你的需求选择)
具体代码示例
下面是一个基于mysqli扩展的完整实现,你可以根据自己的数据库配置调整:
<?php // 源数据库配置 $sourceConfig = [ 'host' => 'localhost', 'user' => 'source_user', 'pass' => 'source_password', 'db' => 'source_database' ]; // 目标数据库配置 $targetConfig = [ 'host' => 'remote_host', // 可以是本地或远程服务器 'user' => 'target_user', 'pass' => 'target_password', 'db' => 'target_database' ]; // 连接源数据库 $sourceConn = new mysqli($sourceConfig['host'], $sourceConfig['user'], $sourceConfig['pass'], $sourceConfig['db']); if ($sourceConn->connect_error) { die("源数据库连接失败: " . $sourceConn->connect_error); } // 连接目标数据库 $targetConn = new mysqli($targetConfig['host'], $targetConfig['user'], $targetConfig['pass'], $targetConfig['db']); if ($targetConn->connect_error) { die("目标数据库连接失败: " . $targetConn->connect_error); } // 获取源数据库所有表 $tablesResult = $sourceConn->query("SHOW TABLES"); if (!$tablesResult) { die("获取源表列表失败: " . $sourceConn->error); } // 逐个处理每个表 while ($tableRow = $tablesResult->fetch_row()) { $tableName = $tableRow[0]; echo "开始处理表: {$tableName}\n"; // 1. 同步表结构:获取源表的创建语句,在目标库执行(如果表不存在) $createTableResult = $sourceConn->query("SHOW CREATE TABLE `{$tableName}`"); $createRow = $createTableResult->fetch_assoc(); $createSql = str_replace($sourceConfig['db'], $targetConfig['db'], $createRow['Create Table']); // 改为CREATE TABLE IF NOT EXISTS,避免表已存在时报错 $createSql = preg_replace('/^CREATE TABLE/', 'CREATE TABLE IF NOT EXISTS', $createSql); if (!$targetConn->query($createSql)) { echo "同步表结构失败({$tableName}): " . $targetConn->error . "\n"; continue; } // 2. 同步表数据:全量覆盖(先清空目标表,再插入),如果需要增量可以用INSERT...ON DUPLICATE KEY UPDATE // 先清空目标表(可选,如果你需要全量备份的话) if (!$targetConn->query("TRUNCATE TABLE `{$tableName}`")) { echo "清空目标表失败({$tableName}): " . $targetConn->error . "\n"; continue; } // 获取源表数据 $dataResult = $sourceConn->query("SELECT * FROM `{$tableName}`"); if (!$dataResult) { echo "获取源表数据失败({$tableName}): " . $sourceConn->error . "\n"; continue; } $columnCount = $dataResult->field_count; if ($columnCount === 0) { echo "表{$tableName}无字段,跳过\n"; continue; } // 生成插入语句的占位符 $placeholders = implode(',', array_fill(0, $columnCount, '?')); $insertSql = "INSERT INTO `{$tableName}` VALUES ({$placeholders})"; $stmt = $targetConn->prepare($insertSql); if (!$stmt) { echo "预处理语句失败({$tableName}): " . $targetConn->error . "\n"; continue; } // 批量插入数据 $rowCount = 0; while ($row = $dataResult->fetch_row()) { // 绑定参数并执行 $params = array_merge([str_repeat('s', $columnCount)], $row); $refParams = []; foreach ($params as $key => $val) { $refParams[$key] = &$params[$key]; } call_user_func_array([$stmt, 'bind_param'], $refParams); if (!$stmt->execute()) { echo "插入数据失败({$tableName}): " . $stmt->error . "\n"; continue; } $rowCount++; } echo "表{$tableName}同步完成,共插入{$rowCount}条数据\n"; $stmt->close(); } // 关闭连接 $sourceConn->close(); $targetConn->close(); echo "所有表同步完成!\n"; ?>
定期执行方案
要实现定期自动备份,你需要借助系统的定时任务工具:
Linux/macOS:使用
crontab。比如每天凌晨2点执行脚本,编辑crontab:crontab -e添加一行:
0 2 * * * /usr/bin/php /path/to/your/backup_script.php >> /path/to/backup_log.log 2>&1这样每天凌晨2点会自动执行脚本,并把日志输出到指定文件。
Windows:使用「任务计划程序」。创建一个新任务,设置触发时间(比如每天凌晨2点),操作选择启动程序,程序路径选你的PHP.exe路径,参数填脚本的绝对路径。
注意事项
- 权限问题:确保源数据库用户有
SELECT权限,目标数据库用户有CREATE、INSERT、TRUNCATE(如果用全量覆盖)权限。 - 大表处理:如果你的表数据量很大,上面的代码一次性读取所有数据可能会导致内存溢出。可以改成分批读取,比如用
LIMIT offset, 1000循环读取直到没有数据。 - 增量备份:如果不需要全量覆盖,而是只同步新增/更新的数据,可以在源表加一个
update_time字段,每次备份只同步update_time大于上次备份时间的数据,或者用INSERT ... ON DUPLICATE KEY UPDATE来处理更新。 - 日志记录:建议在脚本中添加详细的日志记录(比如写入文件),方便出现问题时排查。
- 事务支持:如果需要保证数据一致性,可以在同步数据时开启事务,比如在清空表和插入数据前后加上
$targetConn->begin_transaction()和$targetConn->commit(),出错时回滚。
内容的提问来源于stack exchange,提问作者Rajeev Khulbe
相关产品推荐
相关产品推荐

