能否定义ActiveRecord scope让链式查询执行时自动使用从库?
实现方案
完全可以实现,核心思路是给ActiveRecord::Relation添加从库执行标记,重载其实际执行查询的入口方法,触发查询时自动包裹已有的on_replica块。
具体实现
把以下代码放入Rails应用的初始化文件config/initializers/active_record_replica_extension.rb即可:
module EventuallyOnReplicaExtension extend ActiveSupport::Concern included do # 给查询关系对象添加是否走从库的标记 attr_accessor :should_use_replica # 重载Relation实际执行查询的核心方法 def exec_queries if should_use_replica on_replica { super } else super end end # Relation级别的标记方法,支持链式调用末尾添加标记 def eventually_on_replica self.should_use_replica = true self end end module ClassMethods # 模型类级别的标记方法,支持开头直接调用 def eventually_on_replica all.eventually_on_replica end end end # 注入扩展到ActiveRecord核心逻辑 ActiveRecord::Relation.include EventuallyOnReplicaExtension ActiveRecord::Base.include EventuallyOnReplicaExtension::ClassMethods
效果验证
两种调用形式都可以正常生效:
- 先加查询条件再加标记:
@my_things = MyModel.where(my_attr: "my value").eventually_on_replica # 执行时自动走从库 @my_things.to_a
- 先加标记再加查询条件:
@my_things = MyModel.eventually_on_replica.where(my_attr: "my value") # 执行时自动走从库 @my_things.to_a
注意事项
- 该扩展只对查询操作生效,
create/update/delete等写操作仍会走主库,符合读写分离的常规预期 - 如果原有
on_replica方法已经处理了嵌套场景(比如块内嵌套on_master会优先走主库),该扩展会直接继承原有逻辑,无需额外调整
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

