如何用Prisma在单查询中更新多条不同值的记录
Prisma批量更新多条不同值记录的解决方案
我需要使用Prisma批量更新多条记录,但updateMany只能为符合条件的所有记录设置同一个字段值,无法实现类似SQL中多条UPDATE table SET field = "值N" WHERE id = N的效果。之前尝试的代码无法正常工作:
async updateProductsQuantity( data: IUpdateProductsQuantityDTO ): Promise<void> { await prisma.product.updateMany({ where: { id: { in: data.ids } }, data: { currentQuantity: data.quantities } }); }
方法一:事务+单个Update循环
利用Prisma的事务机制,将多个单个update操作包裹在事务中,保证原子性。这种方式代码简洁、类型安全,适合数据量不大的场景。
async updateProductsQuantity(data: IUpdateProductsQuantityDTO): Promise<void> { // 校验输入合法性,避免长度不匹配导致错误 if (data.ids.length !== data.quantities.length) { throw new Error('ids与quantities数组长度必须一致'); } // 批量生成update操作,通过事务执行 await prisma.$transaction( data.ids.map((id, index) => prisma.product.update({ where: { id }, data: { currentQuantity: data.quantities[index] } }) ) ); }
方法二:原生SQL动态生成CASE语句
通过原生SQL的CASE语法,一次查询完成批量更新,性能更优,适合数据量大的场景。注意要处理SQL注入风险,优先使用参数化查询。
安全的参数化版本(推荐)
async updateProductsQuantity(data: IUpdateProductsQuantityDTO): Promise<void> { if (data.ids.length !== data.quantities.length) { throw new Error('ids与quantities数组长度必须一致'); } const params: (number | string)[] = []; const caseClauses: string[] = []; const inPlaceholders: string[] = []; // 构建参数和SQL片段 data.ids.forEach((id, index) => { params.push(id, data.quantities[index]); // 占位符使用$N格式(适配PostgreSQL,MySQL用?) caseClauses.push(`WHEN id = $${params.length - 1} THEN $${params.length}`); inPlaceholders.push(`$${params.length - 1}`); }); const query = ` UPDATE product SET currentQuantity = CASE ${caseClauses.join(' ')} END WHERE id IN (${inPlaceholders.join(', ')}) `; await prisma.$executeRaw(query, ...params); }
注意事项
- 如果使用MySQL,占位符要换成
?,调整对应的参数索引逻辑。 - 务必使用参数化查询,避免直接拼接用户输入导致SQL注入。
两种方案对比
- 事务循环:优点是代码易维护、Prisma类型校验完整;缺点是数据量过大时会生成多个SQL查询,性能略有下降。
- 原生CASE更新:优点是单查询完成,性能高效;缺点需要手动处理SQL语法和参数化,失去Prisma的类型安全特性。
内容的提问来源于stack exchange,提问作者Caio Pereira
相关产品推荐
相关产品推荐

