【MySQL】node.js 如何批量更新数据?

在 Node.js 中使用 mysql2 库批量更新(Bulk Update)多条数据,主要有三种主流方案。由于 MySQL 本身没有像 INSERT 那样简单的 UPDATE ... VALUES (...) 语法,我们需要根据场景选择最合适的方法。


方法一:使用 CASE WHEN 语句(推荐:单条 SQL 完成)

这是最通用的批量更新方法。通过 SQL 的 CASE 语法,可以根据主键 ID 一次性更新多条记录的不同字段。

适用场景: 更新条数在几十到几百条左右,性能较好。

javascript 复制代码
const mysql = require('mysql2/promise');

async function batchUpdate(data) {
  const connection = await mysql.createConnection({/* config */});

  // 假设 data 结构为: [{id: 1, name: 'A', age: 20}, {id: 2, name: 'B', age: 25}]
  let ids = [];
  let nameCases = '';
  let ageCases = '';
  let params = [];

  data.forEach(item => {
    ids.push(item.id);
    nameCases += `WHEN ? THEN ? `;
    params.push(item.id, item.name);
    
    ageCases += `WHEN ? THEN ? `;
    params.push(item.id, item.age);
  });

  // 最后的 params 顺序需要和 SQL 中的问号顺序一致
  // 这里为了简化演示直接拼接,实际建议通过数组 push 控制顺序
  const sql = `
    UPDATE users 
    SET 
      name = CASE id ${nameCases} END,
      age = CASE id ${ageCases} END
    WHERE id IN (${ids.map(() => '?').join(',')})
  `;

  // 合并参数:[name的id和值..., age的id和值..., WHERE用的id列表]
  const finalParams = [...params, ...ids];

  await connection.execute(sql, finalParams);
}

方法二:使用 INSERT ... ON DUPLICATE KEY UPDATE (性能最高)

如果你的表有主键(Primary Key)唯一索引(Unique Index),这是最高效的方法。它的原理是:尝试插入数据,如果主键冲突,则执行更新。

注意: 如果数据不存在,它会变成插入。如果你只想更新不想插入,需要确保传入的 ID 在数据库中已存在。

javascript 复制代码
const mysql = require('mysql2/promise');

async function batchUpdateUpsert(data) {
  const connection = await mysql.createConnection({/* config */});

  // 将数据转为二维数组: [[1, 'A', 20], [2, 'B', 25]]
  const values = data.map(item => [item.id, item.name, item.age]);

  const sql = `
    INSERT INTO users (id, name, age) 
    VALUES ? 
    ON DUPLICATE KEY UPDATE 
      name = VALUES(name), 
      age = VALUES(age)
  `;

  // mysql2 的 query 方法支持传入二维数组来替换 VALUES ?
  await connection.query(sql, [values]);
}

方法三:使用事务 + 循环更新 (最安全/逻辑最简单)

如果你不熟悉复杂的 SQL 拼接,或者需要对每一条更新进行复杂的逻辑判断,可以使用事务(Transaction)包裹多条 UPDATE 语句。

适用场景: 数据量不大,或者必须保证每条更新的原子性。

javascript 复制代码
const mysql = require('mysql2/promise');

async function batchUpdateTransaction(data) {
  const connection = await mysql.createConnection({/* config */});
  
  try {
    await connection.beginTransaction();

    for (const item of data) {
      await connection.execute(
        'UPDATE users SET name = ?, age = ? WHERE id = ?',
        [item.name, item.age, item.id]
      );
    }

    await connection.commit();
  } catch (error) {
    await connection.rollback();
    throw error;
  }
}

总结与对比

方法 优点 缺点 建议
CASE WHEN 标准 SQL,不依赖唯一键冲突,单次 IO 拼接 SQL 逻辑复杂,数据量过大时 SQL 字符串超长 中等规模更新首选
ON DUPLICATE KEY 速度最快,代码最简洁 必须有主键/唯一索引,会意外插入不存在的数据 超大规模更新首选
事务循环 逻辑最清晰,支持复杂判断 数据库往返 IO 次数多,性能相对较低 小批量或逻辑复杂时使用

💡 进阶技巧:

如果批量更新的数据量达到 万级 以上:

  1. 分批执行: 不要一次性发 10 万条,建议每 500-1000 条作为一组进行批量操作。
  2. 临时表法: 先将数据 LOAD DATA 或批量插入到一个临时表,然后使用 UPDATE users JOIN temp_users ... 的语法进行关联更新。这是处理百万级数据最快的方式。
相关推荐
剩下了什么17 小时前
MySQL JSON_SET() 函数
数据库·mysql·json
山峰哥18 小时前
数据库工程与SQL调优——从索引策略到查询优化的深度实践
数据库·sql·性能优化·编辑器
朝朝暮暮an18 小时前
Day 3|Node.js 异步模型 & Promise / async-await(Part 1)
node.js
较劲男子汉18 小时前
CANN Runtime零拷贝传输技术源码实战 彻底打通Host与Device的数据传输壁垒
运维·服务器·数据库·cann
java搬砖工-苤-初心不变18 小时前
MySQL 主从复制配置完全指南:从原理到实践
数据库·mysql
WangYaolove131420 小时前
基于python的在线水果销售系统(源码+文档)
python·mysql·django·毕业设计·源码
山岚的运维笔记20 小时前
SQL Server笔记 -- 第18章:Views
数据库·笔记·sql·microsoft·sqlserver
roman_日积跬步-终至千里21 小时前
【LangGraph4j】LangGraph4j 核心概念与图编排原理
java·服务器·数据库
汇智信科21 小时前
打破信息孤岛,重构企业效率:汇智信科企业信息系统一体化运营平台
数据库·重构
野犬寒鸦21 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法