Diesel.rs中如何更新带有复合主键的列?
问题分析与修复方案
代码中的核心问题
- 语法错误:
set(times_watched.eq(db_anime_ranking.times_watched += 1))里的+=是 Rust 的赋值操作,不能直接作为eq的参数,这会导致编译失败。 - 逻辑重复:你已经在代码里执行了
db_anime_ranking.times_watched += 1,又在更新语句里再次自增,最终会导致计数多增加1次。 - 低效且有并发风险:先查询再更新的方式不仅多了一次数据库请求,还可能在并发场景下出现竞态条件(比如两个请求同时读取同一条数据,各自加1后写入,最终计数只加了1次)。
修复方案一:修正现有代码逻辑
如果一定要保留先查询的逻辑,只需去掉重复自增,修正语法错误:
for anime_ranking in new_anime_rankings { let mut db_anime_ranking: models::AnimeRanking = anime_rankings .find((anime_ranking.id, anime_ranking.genre_combo_id)) .first(&mut connection)?; println!("{}", db_anime_ranking.id); db_anime_ranking.times_watched += 1; update(anime_rankings.filter((id.eq(anime_ranking.id), genre_combo_id.eq(anime_ranking.genre_combo_id)))) .set(times_watched.eq(db_anime_ranking.times_watched)) // 直接传入更新后的值 .execute(&mut connection)?; }
修复方案二:数据库层面原子自增(推荐)
直接让数据库完成自增操作,无需先查询数据,既高效又能避免并发问题:
for anime_ranking in new_anime_rankings { update(anime_rankings.filter((id.eq(anime_ranking.id), genre_combo_id.eq(anime_ranking.genre_combo_id)))) .set(times_watched.eq(times_watched + 1)) // 数据库层面直接自增,原子操作 .execute(&mut connection)?; }
这种方式利用数据库的原子性操作,确保即使多个请求同时更新同一条数据,计数也能正确累加。
内容的提问来源于stack exchange,提问作者asudox
相关产品推荐
相关产品推荐

