如何在MySQL数据库插入新行时触发发送FCM推送通知
核心疑问解答
- Firebase 本身没有提供官方能力直接连接 MySQL 数据库,也不支持原生监听 MySQL 的行插入/更新事件,直接打通两者的方案无法实现,不需要在这个方向浪费时间。
- 你之前使用 MySQL 触发器直接调用 PHP 脚本的方案本身就存在设计缺陷:触发器会阻塞主插入事务直到外部脚本执行完成,同时还有严格的系统权限限制、异常容错能力差,确实不推荐使用。
可行实现方案(按推荐优先级排序)
方案1:业务代码埋点+异步队列(最优,成本最低)
你现有的 MySQL 插入逻辑肯定是在业务代码中实现的,只需要在插入操作事务提交成功后,触发推送逻辑即可,为了避免推送逻辑影响主接口响应速度,建议搭配简单的异步队列实现:
- 操作步骤:
- 插入数据成功并确认事务提交后,不要直接调用 FCM 推送逻辑,将需要推送的参数存入 Redis 等内存队列
- 单独用 CLI 模式运行一个常驻的消费脚本,从队列中取出任务执行你已经写好的 FCM 推送逻辑
- 示例代码:
// 主业务插入逻辑部分 $pdo = new PDO($dsn, $user, $pass); $insertStmt = $pdo->prepare("INSERT INTO 你的目标表 (字段1,字段2) VALUES (?,?)"); $insertResult = $insertStmt->execute([$val1, $val2]); if ($insertResult && $newId = $pdo->lastInsertId()) { // 将推送所需数据写入Redis队列 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->lPush('fcm_push_queue', json_encode([ 'id' => $newId, 'content' => $val1 ])); }
// 队列消费脚本 fcm_consumer.php,CLI模式运行即可 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); while (true) { $job = $redis->rPop('fcm_push_queue'); if ($job) { $pushData = json_decode($job, true); // 调用你已经调试好的FCM推送函数 yourExistingFcmPushFunction($pushData); } else { // 无任务时休眠1秒降低CPU占用 sleep(1); } }
- 优势:完全复用你现有的推送逻辑,性能高、逻辑可控,不会影响主业务的插入性能,异常容错能力强。
方案2:监听MySQL Binlog(无侵入业务代码方案)
如果你的插入逻辑散落在多个系统无法统一修改,或者插入操作不由你维护的代码触发,可以选择监听 MySQL Binlog 实现:
- 操作步骤:
- 开启 MySQL 的 Binlog 功能,配置为 ROW 行模式
- 使用 Binlog 解析工具,订阅指定库表的 INSERT 事件
- 捕获到新行插入事件后,拿到行数据调用 FCM 推送接口
- 优势:完全不需要修改现有业务代码,和插入逻辑完全解耦,实时性高。
方案3:定时轮询(简易应急方案)
如果你的实时性要求不高(允许1~5分钟延迟),可以用最简单的定时轮询方案:
- 操作步骤:
- 记录上次查询到的目标表最大自增ID(或最大创建时间)
- 用 Crontab 定时执行脚本,查询目标表中ID大于上次记录值的所有新行
- 逐行触发FCM推送,更新记录的最大ID值
- 优势:实现成本极低,不需要改配置也不需要改现有业务逻辑
- 劣势:存在推送延迟,轮询频率过高会增加数据库压力。
触发器方案优化(如果必须用数据库侧触发逻辑)
如果一定要在数据库层面触发推送,不要直接调用外部PHP脚本,可以改成触发器将新插入的行ID写入一个专门的fcm_push_queue队列表,后台单独运行脚本扫描队列表处理推送,推完标记为已处理即可,该方案不会阻塞主插入事务,稳定性远高于直接调用外部脚本。
内容的提问来源于stack exchange,提问作者aziz laroussi
相关产品推荐
相关产品推荐

