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
相关产品推荐
相关产品推荐

