多次执行INSERT语句仅首次生效 求排查原因(附代码)
嘿,我来帮你排查这个「多次INSERT仅首次生效」的问题——这种悄无声息没报错但不干活的情况,多半是这几个常见坑:
可能的原因&解决办法
1. 异步循环没处理好(最常见!)
很多时候咱们用forEach或者普通循环处理异步的数据库操作,比如connection.query()是异步的,forEach不会等待它完成就直接跑下一次,结果可能只有第一个请求发出去了,后面的因为异步时序问题没执行,或者被吞了。
解决办法:改用for...of循环配合await(如果用的是promise版的数据库驱动),或者确保每个异步操作完成后再执行下一个。比如:
原来的错误写法:
// 用forEach处理异步,大概率会出问题 scrapedData.forEach(item => { db.query('INSERT INTO posts (title, url) VALUES (?, ?)', [item.title, item.url], (err) => { if (err) console.log(err); // 可能没捕获到错误! }); });
改成正确的异步等待写法:
// 用for...of + await,确保每次插入完成再继续 for (const item of scrapedData) { try { // 用promise版的查询(比如mysql2/pg都支持) await db.promise().query('INSERT INTO posts (title, url) VALUES (?, ?)', [item.title, item.url]); console.log(`成功插入:${item.title}`); } catch (err) { // 一定要捕获错误!不然出问题也不知道 console.error(`插入失败:${item.title}`, err.message); } }
2. 数据库事务没提交
如果你的代码里开启了事务(比如connection.beginTransaction()),但第一次插入后没调用connection.commit(),那后续的插入都在同一个未提交的事务里,数据库不会真正写入,看起来就像没执行。
解决办法:检查代码里的事务逻辑,确保每次插入后(或者循环结束后)提交事务,或者如果不需要事务就别开启。比如:
// 如果用了事务,记得提交 await db.promise().beginTransaction(); try { for (const item of scrapedData) { await db.promise().query('INSERT INTO posts SET ?', item); } await db.promise().commit(); // 必须提交! } catch (err) { await db.promise().rollback(); // 出错回滚 console.error('事务失败:', err); }
3. 重复数据触发唯一约束(但你没捕获错误)
如果数据库表的某个字段设置了唯一约束(比如url字段是UNIQUE),后续抓取的数据和第一次重复,INSERT会失败,但如果你的代码没捕获错误,就会误以为没执行。
解决办法:
- 先检查数据库表的结构,看有没有唯一键约束
- 在代码里强制捕获错误,打印出来看看是不是约束冲突
- 如果允许重复插入(或者想跳过重复),可以用
INSERT IGNORE或者ON DUPLICATE KEY UPDATE:
INSERT INTO posts (title, url) VALUES (?, ?) ON DUPLICATE KEY UPDATE title = VALUES(title);
4. 后续抓取的数据为空
有可能Cheerio后续抓取的内容是空的(比如页面结构变化,或者循环里的选择器写错了),导致INSERT的参数是空值,数据库允许空值的话就不会报错,但实际上没插入有效数据。
解决办法:在INSERT之前加个判断,打印每次要插入的数据,确认数据存在:
for (const item of scrapedData) { // 先检查数据是否有效 if (!item.title || !item.url) { console.log('跳过空数据:', item); continue; } // 再执行插入 await db.promise().query('INSERT INTO posts SET ?', item); }
快速排查步骤
- 先打印所有要插入的
scrapedData,确认数组里有多个有效数据 - 在数据库查询的回调/try-catch里强制打印错误,看有没有隐藏的报错
- 直接在数据库客户端手动执行几次INSERT语句,看是否能成功插入多条
- 检查数据库连接是否在循环中被意外关闭或释放
内容的提问来源于stack exchange,提问作者mokiliii Lo
相关产品推荐
相关产品推荐

