You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NodeJS应用向MySQL重复插入数据的原因排查求助

重复插入问题排查与解决建议

1. 先确认MQTT消息是否被重复接收/处理

  • 检查是否多次绑定了message事件:如果你的应用初始化逻辑重复执行(比如多次实例化MQTT客户端或消息处理类),会导致同一个消息被多个监听器捕获,触发多次插入。可以在绑定事件前先调用this.client.removeAllListeners('message'),避免重复绑定。
  • 核实MQTT消息的QoS级别:如果设备用QoS 1/2发送消息,客户端确认超时的情况下,Mosquitto会重复推送消息。可以临时将QoS改为0测试,看是否还会出现重复插入。

2. 修复数据库连接池重复初始化问题

你的findDevice和insertLog每次执行都会调用await this.init(),而init方法每次都会重新创建连接池(this.pool = mysql.createPool(...)),多次创建连接池可能导致连接混乱,引发重复执行SQL的情况。
修改init方法,保证只初始化一次:

async init() {
  if (this.pool) return; // 已有连接池,直接返回
  try {
    this.pool = mysql.createPool({
      host: process.env.DBHOST,
      user: process.env.DBUSER,
      password: process.env.DBPASS,
      database: process.env.DBNAME,
      waitForConnections: true,
      connectionLimit: 5, // 适当提高连接数,1可能导致请求堆积
      queueLimit: 0 // 取消队列限制,避免请求阻塞
    });
    console.log('Database pool established successfully');
  } catch (error) {
    console.error('Error creating database pool: ', error);
  }
}

3. 检查是否存在多个业务类实例

确认messageReceivedViewModel、existingDeviceViewModel、activityLogViewModel这些类是否被多次实例化。如果应用中创建了多个同类实例,同一个MQTT消息会被每个实例分别处理,导致多次插入。

4. 数据库端排查

  • 检查activity_log表是否存在自动复制行的触发器,部分触发器逻辑可能导致控制台显示插入1行,但数据库实际生成重复数据。
  • 开启MySQL的通用查询日志(general_log),查看数据库实际接收到多少次INSERT语句,确认是应用触发多次插入,还是数据库内部问题。

5. 增加跟踪日志定位问题

给每条MQTT消息添加唯一标识,跟踪完整处理流程,确认是否是同一条消息被重复处理:

const crypto = require('crypto');

// 在MQTT消息监听器中添加唯一ID
this.client.on('message', (topic, message) => {
  const msgId = crypto.randomUUID();
  const dato = { topic, message: message.toString(), msgId };
  console.log(`[${msgId}] Message received: ${JSON.stringify(dato)}`);
  this.messageReceivedViewModel.handleMessage(dato);
});

然后在checkDevice、logActivity、insertLog方法中都打印这个msgId,如果同一个msgId多次出现在日志中,说明消息被重复处理了。

内容的提问来源于stack exchange,提问作者Pedro Reyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:16:27