为什么TypeORM v0.2.40操作MySQL时未修改数据也返回affected:1
问题根因
- MySQL/MariaDB默认返回的
affectedRows字段统计的是WHERE条件匹配到的行数,而非实际发生数据修改的行数,实际修改行数存储在返回结果的changedRows字段中。 - TypeORM v0.2.40版本处理MySQL/MariaDB的更新返回结果时,直接将驱动返回的
affectedRows赋值给UpdateResult.affected字段,未做changedRows的映射处理,因此只要匹配到数据,无论内容是否变更,都会返回affected: 1。 - 原生查询会返回完整的
ResultSetHeader结构,因此可以直接读取changedRows判断实际修改情况,但TypeORM封装的更新方法默认不会将该字段暴露到外层返回结果中。
可行解决方案
方案1:修改数据库连接配置(适合无
FOUND_ROWS()函数依赖的场景)
在TypeORM的连接配置extra参数中添加禁用FOUND_ROWS的标志,修改后MySQL会直接将实际修改行数赋值给affectedRows,TypeORM返回的affected字段就会符合预期:// ormconfig 配置示例 export default { type: "mysql", host: "127.0.0.1", port: 3306, username: "root", password: "your password", database: "your db", // 新增以下配置 extra: { flags: "-FOUND_ROWS" } }注意:该配置会导致
FOUND_ROWS()统计函数失效,如果项目中用该函数实现分页总条数统计,请选择其他方案方案2:封装自定义更新方法(适合不能修改连接配置、不想升级TypeORM的场景)
利用TypeORM的查询构建器生成SQL,再通过原生查询执行,直接解析返回结果的changedRows字段,无需手动编写全量SQL:import { Repository, UpdateResult } from "typeorm"; async function updateWithRealAffected<T>( repo: Repository<T>, id: number | string, updateData: Partial<T>, idKey = "id" ): Promise<number> { const qb = repo .createQueryBuilder() .update(updateData) .where(`${idKey} = :id`, { id }); const [sql, params] = qb.getQueryAndParameters(); const result = await repo.manager.query(sql, params); return result.changedRows; } // 调用示例 const affected = await updateWithRealAffected(areaRepo, id, data, "area_id");方案3:升级TypeORM版本(适合可以接受版本迭代break change的场景)
TypeORM v0.3.10及以上版本已经优化了MySQL/MariaDB的更新返回逻辑,会自动将changedRows的值映射到UpdateResult.affected字段,升级后无需额外配置即可符合预期。
内容的提问来源于stack exchange,提问作者Benny
相关产品推荐
相关产品推荐

