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

Sequelize更新记录时MySQL与SQLite的.forEach()行为不一致问题

Sequelize中forEach异步更新MySQL不生效,for-of正常的问题分析与解决

问题现象

使用Node.js 20.12.2 + Sequelize 6.37.3搭配MySQL时,通过.forEach()遍历findAll()结果更新记录,更新操作未生效;但使用for (const ... of ...)循环时更新正常。而在SQLite环境下,两种遍历方式都能正确更新。

测试代码如下:

const Sequelize = require('sequelize');

let db;
if (0) {
  // SQLite case:
  db = new Sequelize({
    dialect: 'sqlite',
    storage: ':memory:',
  });
} else {
  // MySQL case:
  db = new Sequelize({
    dialect: 'mysql',
    hostname: '127.0.0.1',
    username: 'root',
    password: process.env.DB_PASSWORD,
    database: 'test',
  });
}

(async () => {
  const Foo = db.define('Foo', {
    bar: Sequelize.DataTypes.STRING,
  });

  // 创建表
  await Foo.sync({
    force: true
  });

  // 插入测试数据
  await Foo.create({
    bar: 'abc',
  });

  // forEach 测试
  let items = await Foo.findAll();
  console.log(items[0].bar);

  items.forEach(async item => {
    item.bar = 'forEach';
    await item.save();
  });
  items = await Foo.findAll();
  console.log(items[0].bar);

  // for-of 测试
  items = await Foo.findAll();
  console.log(items[0].bar);

  for (const item of items) {
    item.bar = 'for-of';
    await item.save();
  };
  items = await Foo.findAll();
  console.log(items[0].bar);
})().finally(() => {
  process.exit();
});

执行日志对比

  • SQLite日志:forEach更新后,后续findAll能读取到forEach值
  • MySQL日志:forEach更新后,后续findAll仍读取到旧值abc,直到for-of执行后才更新为for-of

问题原因

核心差异在于异步函数的等待机制:

  • .forEach()方法不会等待传入的异步函数执行完成,调用后会立即继续执行后续代码。MySQL是磁盘数据库,IO操作有延迟,导致await Foo.findAll()在item.save()完成前就执行,读取到的是未更新的数据。
  • for-of循环会在每次迭代中等待await item.save()完成,确保更新操作执行完毕后才进入下一步,后续的findAll能读取到最新数据。
  • SQLite作为内存数据库,IO速度极快,forEach中的save()可能刚好在findAll()前完成,导致看起来生效,但这是不可靠的偶然情况。

解决方案

将forEach替换为支持异步等待的遍历方式,两种可选方案:

方案1:使用for-of循环(已验证有效)

保持现有for-of的写法,确保每次更新都等待完成:

for (const item of items) {
  item.bar = 'forEach';
  await item.save();
}

方案2:使用Promise.all()配合map()

适合需要并行执行更新的场景,等待所有更新完成后再执行后续操作:

await Promise.all(items.map(async item => {
  item.bar = 'forEach';
  await item.save();
}));

修改后,MySQL环境下也能正确读取到更新后的数据。

内容的提问来源于stack exchange,提问作者Gea-Suan Lin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:37:14