本文目录导读:

- 场景一:从库 A 同步到库 B(主从复制、ETL)
- 场景二:PHP 与第三方 API 数据同步
- 场景三:文件数据同步(如CSV、Excel导入)
- 场景四:Redis / 缓存与数据库同步
- 核心注意事项
- 推荐的工具/类库
- 总结:你应该选择哪种方式?
PHP 数据同步是一个比较大的话题,因为“同步”的目标不同(数据库、第三方API、文件、Redis缓存等),实现方式也不同。
为了给你最实用的答案,我将其分为最常见的数据同步场景并分别给出代码示例和方案。
从库 A 同步到库 B(主从复制、ETL)
这是最典型的需求,比如把线上库的数据同步到报表库。
方案 1:基于时间戳 / 自增ID 的增量同步(推荐)
适用于源表有 updated_at 或自增 id 的情况。
<?php
//源库连接(MySQL)
$sourceDb = new PDO('mysql:host=source_host;dbname=source_db', 'user', 'pass');
//目标库连接
$targetDb = new PDO('mysql:host=target_host;dbname=target_db', 'user', 'pass');
//假设同步用户表,记录最后同步的ID
$lastSyncId = getLastSyncId(); //从记录表中读取上次同步到的ID
$batchSize = 1000;
$stmt = $sourceDb->prepare("SELECT * FROM users WHERE id > ? ORDER BY id ASC LIMIT ?");
$stmt->execute([$lastSyncId, $batchSize]);
$insertStmt = $targetDb->prepare("REPLACE INTO users (id, name, email, created_at) VALUES (?, ?, ?, ?)");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$insertStmt->execute([
$row['id'],
$row['name'],
$row['email'],
$row['created_at']
]);
//更新最后同步的ID
updateLastSyncId($row['id']);
}
echo "同步完成,最后ID: " . $lastSyncId;
?>
方案 2:MySQL Binlog 实时监听(高级)
使用 canal 或 mysql-binlog-connector-java,然后用 PHP 消费,但这通常需要 PHP 作为消费者配合 Kafka/Redis 使用,纯 PHP 实现较少且性能一般。
PHP 与第三方 API 数据同步
订单创建后同步到 ERP 系统(金蝶、SAP),或用户信息同步到推送服务。
推荐:消息队列 + 异步消费
<?php
//生产端:创建订单后发送到队列
function createOrder($orderData) {
// ... 本地数据库插入操作
// 同步发送到队列
$queue = new RedisQueue(); //假设封装好的Redis队列
$queue->push('sync:erp:order', json_encode($orderData));
return true;
}
//消费端:独立脚本或Worker(swoole/Workerman)
while (true) {
$orderData = $queue->pop('sync:erp:order');
if ($orderData) {
$order = json_decode($orderData, true);
try {
$erpApi = new ErpApi();
$erpApi->syncOrder($order);
logSyncSuccess($order['id']);
} catch (Exception $e) {
// 记录失败,重试机制
$queue->retry('sync:erp:order:fail', $orderData);
}
}
}
文件数据同步(如CSV、Excel导入)
<?php
//读取CSV并同步到数据库
$file = fopen('data.csv', 'r');
$headers = fgetcsv($file); //跳过标题行
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'pass');
$stmt = $db->prepare("INSERT INTO products (sku, name, price, stock) VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE name=VALUES(name), price=VALUES(price)");
while (($row = fgetcsv($file)) !== false) {
$stmt->execute([
$row[0], //sku
$row[1], //name
$row[2], //price
$row[3] //stock
]);
}
fclose($file);
echo "文件同步完成";
?>
Redis / 缓存与数据库同步
方案:Cache-Aside 模式
<?php
//读取数据:先查缓存,再查库,回写缓存
function getUser($userId) {
$cache = new Redis();
$user = $cache->get("user:$userId");
if (!$user) {
// 同步:从数据库加载
$user = $db->query("SELECT * FROM users WHERE id = $userId")->fetch();
if ($user) {
$cache->set("user:$userId", json_encode($user), 3600);
}
} else {
$user = json_decode($user, true);
}
return $user;
}
//更新数据:先更新数据库,再删除缓存
function updateUser($userId, $data) {
$db->update("users", $data, "id = $userId");
$cache->del("user:$userId"); //删除缓存,下次读取自动同步
}
?>
核心注意事项
- 事务与一致性:同步操作需要保证原子性,使用数据库事务。
- 失败重试:API同步或队列消费必须有重试机制,否则数据会丢失。
- 锁与并发:如果多个进程同时同步同一张表,会导致数据错乱,使用
SELECT ... FOR UPDATE或 Redis 分布式锁。 - 性能考量:
- 小批量(如1000条一批)
- 不要用
SELECT *除非所有字段都需要 - 使用
INSERT ... ON DUPLICATE KEY UPDATE代替先查后改
- 记录同步状态:建立一个
sync_log表,记录最后一次的同步时间、ID、状态等。
推荐的工具/类库
- 数据库同步:
phpMyAdmin的同步功能(适合页面操作)、MySQL Workbench、pt-table-sync(Percona Toolkit)。 - ETL 框架:Apache Airflow(调度)、Talend(重量级)、Kettle。
- PHP 中间件:supervisor(管理常驻进程)、Swoole(异步高性能)、Laravel Horizon(队列监控)。
你应该选择哪种方式?
- 一次性全量同步:直接用
mysqldump导入导出,或用 PHP 脚本分页读取写入。 - 定期增量同步(分钟~小时级):使用方案一(时间戳/ID)。
- 实时同步(秒级):使用Binlog + Canal + Kafka,PHP 作为消费者。
- 跨系统API同步:使用消息队列,保证不丢数据。
如果你能告诉我具体要同步什么(数据库到数据库?到API?文件?)和数据量级(几百条?几千万?),我能给出更精准的代码。