PHP项目数据同步如何跨库实时同步数据表

wen PHP项目 28

本文目录导读:

PHP项目数据同步如何跨库实时同步数据表

  1. 方案一:MySQL主从复制(最推荐,真正的实时同步)
  2. 方案二:触发器 + MySQL UDF/HTTP请求(适用中小项目)
  3. 方案三:Canal/DeCanal(阿里开源,适合高并发)
  4. 方案四:PHP脚本定时轮询(最不推荐,但有特殊场景)
  5. 如何选择(决策树)
  6. 注意事项

针对PHP项目的跨库实时数据同步,有几种主流的实现方案,由于PHP本身是同步阻塞的脚本语言,实现真正的“实时”(毫秒级)同步通常需要借助数据库自身机制或中间件。

以下是几种常用方案,从简单到复杂,按适用场景排序:

MySQL主从复制(最推荐,真正的实时同步)

这是MySQL原生支持的方案,性能高、延迟低(毫秒级),无需修改PHP代码。

原理
源库(Master)将数据变更写入binlog(二进制日志),目标库(Slave)通过IO线程拉取并重放这些日志。

实现步骤

  1. 配置源库(开启binlog)
    -- my.cnf
    [mysqld]
    log-bin=mysql-bin
    server-id=1
    binlog-do-db=source_db   # 只同步指定库
  2. 配置目标库
    [mysqld]
    server-id=2
    relay-log=mysql-relay-bin
    replicate-do-db=target_db
  3. 创建复制用户
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'target_host' IDENTIFIED BY 'password';
  4. 执行同步命令(在目标库)
    CHANGE MASTER TO MASTER_HOST='source_host',MASTER_USER='repl',MASTER_PASSWORD='password',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=0;
    START SLAVE;

优点

  • 无需代码,数据库自带功能,稳定可靠
  • 延迟极低(< 1秒)
  • 支持异构库名(如 source_db.user 同步到 target_db.user_copy

缺点

  • 必须使用MySQL双方
  • 需要两个数据库的网络连通

触发器 + MySQL UDF/HTTP请求(适用中小项目)

如果数据库不同(如MySQL同步到PostgreSQL或SQL Server),或者需要实时触发PHP业务逻辑,可用此方案。

原理
在源表上创建触发器,每次INSERT/UPDATE/DELETE时,调用MySQL的sys_exec()或HTTP请求(通过mysql-udf-http插件)通知PHP脚本。

示例(MySQL触发器中调用PHP接口):

-- 需要安装 mysql-udf-http 插件
CREATE TRIGGER sync_user AFTER INSERT ON user
FOR EACH ROW
BEGIN
   DECLARE result INT;
   SET result = sys_exec(CONCAT('curl -s "http://sync-server/sync.php?table=user&action=insert&id=', NEW.id, '"'));
END;

PHP接收端(sync.php):

<?php
$table = $_GET['table'];
$action = $_GET['action'];
// 根据参数执行跨库SQL操作
$targetDb = new PDO(`mysql:host=target_db...`);
$targetDb->exec(`INSERT INTO {$table} ...`);

优点

  • 支持异构数据库(PHP里自由操作任何DB)
  • 可以触发复杂业务逻辑(如数据转换、发送通知)

缺点

  • 对MySQL性能有影响(每次DML都要额外执行HTTP请求)
  • 延迟取决于网络和PHP处理速度(通常几十到几百ms)
  • 触发器失控风险(出现错误不易排查)

Canal/DeCanal(阿里开源,适合高并发)

Canal模拟MySQL从库协议,解析binlog并推送给PHP消费端,适合需要高吞吐、低延迟的场景。

架构
MySQL binlog -> Canal -> (kafka/RabbitMQ) -> PHP Consumer

PHP端代码示例(使用canal-php库):

$client = new CanalClient('127.0.0.1', 11111);
$client->subscribe('your_filter');
while (true) {
    $messages = $client->get(100);
    foreach ($messages as $msg) {
        $rowData = $msg['rowData'];
        // 解析表名、操作(INSERT/UPDATE/DELETE)和字段
        syncToTargetDb($rowData);
    }
}

优点

  • 对源库几乎零侵入(仅需开启binlog)
  • 支持非常高的并发和延迟要求
  • 支持多消费者(可同时同步到多个目标库)

缺点

  • 需要额外部署Java环境(Canal本身是Java写的)
  • 学习成本高

PHP脚本定时轮询(最不推荐,但有特殊场景)

仅适合对实时性要求不高的场景(如每小时同步一次)。

原理
PHP脚本(Crontab)定期查询源库的变更记录(比如有一个updated_at字段):

SELECT * FROM user WHERE updated_at > '$last_sync_time';

PHP脚本

$lastSyncTime = file_get_contents('last_sync.txt');
$sourceDb = new PDO(...);
$targetDb = new PDO(...);
$rows = $sourceDb->query("SELECT * FROM user WHERE updated_at > '$lastSyncTime'");
foreach ($rows as $row) {
    $targetDb->exec("REPLACE INTO user (id, name) VALUES ({$row['id']}, '{$row['name']}')");
}
file_put_contents('last_sync.txt', date('Y-m-d H:i:s'));

优点

  • 实现最简单
  • 兼容任何数据库

缺点

  • 延迟高(分钟级到小时级)
  • 无法捕获删除操作(除非用软删除)
  • 高并发下重复同步压力大

如何选择(决策树)

需求 推荐方案
双方都是MySQL,要求毫秒级 主从复制(方案一)
不同数据库(MySQL → PostgreSQL等) 触发器+PHP(方案二)
高并发、需要可靠的消息队列 Canal + Kafka(方案三)
实时性要求不高的内部系统 PHP定时轮询(方案四)
需要同步时转换数据格式 方案二或三,在PHP中处理

注意事项

  1. 主键冲突:跨库同步时,注意主键是否自增,建议使用uuid或全局唯一ID,避免冲突。
  2. 死锁:如果两个库互相读写,可能形成循环复制,需要设置ignore-table
  3. 性能监控:主从复制用SHOW SLAVE STATUS查看Seconds_Behind_Master;Canal用JMX监控消费速度。
  4. 失败回滚:建议在PHP客户端(方案二/三)加入重试机制和死信队列。

最推荐方案一(主从复制),简单稳定,大部分场景够用,如果确实需要异构数据库,再考虑方案二或三。

抱歉,评论功能暂时关闭!