Rails中一对多关联counter_cache无法正确重新加载问题
Rails乐观锁下Counter Cache删除后不更新的解决方案
问题场景
创建包含lock_version和comments_count字段的Post模型,与comments建立has_many关联;创建包含lock_version字段的Comment模型,与post建立belongs_to关联并启用counter_cache: true。执行删除评论操作后,post.comments_count未正确递减:
class Post < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :post, counter_cache: true end post = Post.create! comment = Comment.create(post: post) puts post.reload.comments_count # 1 (正确) Comment.last.destroy puts post.reload.comments_count # 1 (应为0 - 错误)
问题根源
当父模型(Post)启用乐观锁(存在lock_version字段)时,Rails默认的counter_cache更新逻辑是直接执行一条不带lock_version的UPDATE语句修改comments_count。由于乐观锁要求更新操作必须携带当前lock_version值,这条UPDATE会被乐观锁拦截,导致计数无法更新。
解决方案
方案一:手动维护计数并处理乐观锁
在Comment模型中添加回调,使用with_lock锁定父模型并更新计数,with_lock会自动处理乐观锁的重试逻辑:
class Comment < ActiveRecord::Base belongs_to :post, counter_cache: true before_destroy :update_post_comment_count_with_lock private def update_post_comment_count_with_lock post.with_lock do post.decrement!(:comments_count) end end end
方案二:完全手动维护计数
移除默认counter_cache配置,通过回调在评论创建/销毁时手动更新父模型计数:
class Post < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :post after_create :increment_post_comment_count before_destroy :decrement_post_comment_count private def increment_post_comment_count post.with_lock do post.increment!(:comments_count) end end def decrement_post_comment_count post.with_lock do post.decrement!(:comments_count) end end end
内容的提问来源于stack exchange,提问作者maximhorse314
相关产品推荐
相关产品推荐

