You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:42:50