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

如何同时插入含外键关联的两张表并批量处理数组插入数据

关联表批量插入与自增ID获取优化方案

1. 准确获取刚插入表a的自增ID

用SELECT * FROM a ORDER BY id DESC LIMIT 1存在并发风险——如果同时有其他请求插入表a,拿到的可能不是当前请求生成的ID。更可靠的方案有两种:

方案一:利用数据库内置函数(以MySQL为例)

在插入表a后,直接调用驱动返回结果中的insertId字段,这个值是会话隔离的,不会被其他请求干扰:

const insertAResult = await myDataSource.query(
  `INSERT INTO a (user_id, a_data) VALUES (?,?)`,
  [user_id, a_data]
);
// 从插入结果中直接获取当前会话生成的自增ID
const aId = insertAResult.insertId;

方案二:依赖驱动返回的插入结果

如果使用mysql2这类驱动,执行INSERT语句后返回的结果对象会直接包含insertId字段,这是最直接且安全的方式,无需额外查询。

2. 处理数组格式请求体并批量插入表b

针对req.body中typeId和figure两个对应数组的情况,需先将两个数组的元素按索引配对,生成批量插入的参数列表,再构造批量INSERT语句:

步骤说明:

  • 先校验两个数组长度是否一致(避免数据错位)
  • 遍历数组,将每一组[aId, typeId[i], figure[i]]整理成参数数组
  • 构造包含多组VALUES的INSERT语句,用占位符对应参数

具体实现

// 从req.body中取出数据
const { typeId, figure } = req.body;

// 校验数组长度一致
if (typeId.length !== figure.length) {
  throw new Error("typeId与figure数组长度不匹配");
}

// 生成批量插入的参数列表
const batchParams = typeId.map((id, index) => [aId, id, figure[index]]);

构造批量插入SQL并执行:

const insertBResult = await myDataSource.query(
  `INSERT INTO b(a_id, type_id, count) VALUES ${batchParams.map(() => "(?,?,?)").join(",")}`,
  batchParams.flat() // 将二维数组拍平成一维,对应占位符顺序
);

完整修正后的DAO代码

const createData = async(user_id, a_data, reqBody) => {
  // 插入表a并获取自增ID
  const insertAResult = await myDataSource.query(
    `INSERT INTO a (user_id, a_data) VALUES (?,?)`,
    [user_id, a_data]
  );
  const aId = insertAResult.insertId;

  const { typeId, figure } = reqBody;
  // 校验数组长度
  if (typeId.length !== figure.length) {
    throw new Error("typeId与figure数组长度必须一致");
  }

  // 生成批量插入参数
  const batchParams = typeId.map((tid, idx) => [aId, tid, figure[idx]]);
  
  // 批量插入表b
  const insertBResult = await myDataSource.query(
    `INSERT INTO b(a_id, type_id, count) VALUES ${batchParams.map(() => "(?,?,?)").join(",")}`,
    batchParams.flat()
  );

  return { insertAResult, insertBResult };
};

额外优化:事务保证数据一致性

建议用事务包裹两次插入操作,避免表a插入成功但表b插入失败导致的数据不一致:

const createData = async(user_id, a_data, reqBody) => {
  const connection = await myDataSource.getConnection();
  await connection.beginTransaction();
  try {
    // 插入表a
    const insertAResult = await connection.query(
      `INSERT INTO a (user_id, a_data) VALUES (?,?)`,
      [user_id, a_data]
    );
    const aId = insertAResult.insertId;

    const { typeId, figure } = reqBody;
    if (typeId.length !== figure.length) {
      throw new Error("typeId与figure数组长度必须一致");
    }

    const batchParams = typeId.map((tid, idx) => [aId, tid, figure[idx]]);
    const insertBResult = await connection.query(
      `INSERT INTO b(a_id, type_id, count) VALUES ${batchParams.map(() => "(?,?,?)").join(",")}`,
      batchParams.flat()
    );

    await connection.commit();
    return { insertAResult, insertBResult };
  } catch (err) {
    await connection.rollback();
    throw err;
  } finally {
    await connection.release();
  }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:50:27