Sequelize Model.increment 返回 [undefined, 行数] 而非预期的受影响行数组
Sequelize调用increment方法无法返回受影响行的问题解决
核心原因
你拿到[undefined, 受影响行数]的返回结果,是两个客观限制共同导致的:
- 数据库特性限制:
returning: true参数依赖数据库原生支持RETURNING查询子句,目前仅PostgreSQL、SQL Server、Oracle这类数据库支持该特性。如果使用MySQL、SQLite等不支持该子句的数据库,哪怕配置了returning参数,数据库本身不会返回更新后的行数据,Sequelize自然无法填充结果数组的第一位,最终返回undefined。 - 方法设计差异:就算使用支持RETURNING的数据库,Sequelize的
increment方法对返回值的处理逻辑和普通的findAll、update方法并不一致——不少旧版本的Sequelize中,仅传布尔值形式的returning: true不会触发自动反序列化,无法把数据库返回的行转换为模型实例填充到返回结果中。
可落地的解决方案
针对支持RETURNING子句的数据库(PostgreSQL等)
调整increment的参数传值方式,不要直接使用布尔值作为returning的取值,显式指定要返回的字段列表,同时把增量配置从字符串形式改为对象形式,避免版本兼容问题:
let DBResults = await searchModel.increment( // 把要做增量的字段和增量值绑定为对象,代替原来的字符串字段名传参 { SearchesCounter: 1 }, { where: { Name: { [Op.or]: searches, }, }, // 用字段数组代替布尔值true,显式声明需要返回所有受影响行的全部字段 returning: ['*'], } );
调整后返回结果的第一位就会填充对应的受影响行模型实例,和预期的返回结构一致。
针对不支持RETURNING子句的数据库(MySQL、SQLite等)
这类场景下无法依赖数据库特性直接拿到更新后的行,最稳妥的方案是保持原有increment的原子更新逻辑不变,在更新完成后用完全相同的查询条件拉取对应行记录:
// 第一步:无依赖完成计数器的原子增量更新,和原有逻辑完全一致 await searchModel.increment("SearchesCounter", { by: 1, where: { Name: { [Op.or]: searches, }, }, }); // 第二步:匹配完全相同的条件查询更新后的行数据 const affectedRows = await searchModel.findAll({ where: { Name: { [Op.or]: searches, }, }, });
注意:因为你的查询条件基于带唯一索引的
Name字段,单次findAll的查询速度极快,不会产生明显的性能损耗;同时这种写法不依赖特定数据库的私有特性,换数据库时不会出现兼容问题。另外不要用普通的update方法计算增量值替代increment,普通update的非原子计算在高并发场景下会出现计数器值被覆盖的问题。
内容的提问来源于stack exchange,提问作者eliezra236
相关产品推荐
相关产品推荐

