当前位置: 首页 > 工具软件 > Rails > 使用案例 >

Rails 缓存

黄鸣
2023-12-01

Rails 缓存

caching_with_rails 中介绍了 Rails 缓存的相关内容;

我结合工作中的使用写下了本篇文章; 部分内容翻译自 rails 的官方文档;

简介

缓存(cache)是一种提高应用性能的高效方式;
通过缓存, 应用可以在一台服务器和单一的数据库下, 维持上千的并发用户;

Rails 提供了一系列开箱即用的功能;
掌握这些技术, 你的 Rails 应用可以服务上百网的浏览器, 并且不需要过高的响应事件和服务器要求;

注意: rails 的缓存默认只有在 production 下才会生效;
示例代码, 需要在 production 下执行;

# 指定使用 production
rails c -e production

因为工作中很少用到, 因此省去了页面缓存的部分内容;

low-level caching

Rails 提供了一个 low-level caching 的 api; 开箱即用;

Rails.cache.fetch 第一个参数 key, 第二参数 hash; expires_in 表示过期时间;

当 fetch 不到值时, 才会执行 block;

class Product < ApplicationRecord
  def competing_price
    Rails.cache.fetch("#{cache_key_with_version}/competing_price", expires_in: 12.hours) do
      puts '没有值的时候, 才会执行'
      Competitor::API.find_price(id)
    end
  end
end

注意: 上面的代码中, 我们使用到了 cache_key_with_version, 这个方法会返回例如 products/233-20140225082222765838000/competing_price; 会根据 model 的类名, id, 和 update_at 属性来生成;

使用场景:

  • 不经常更新的数据, 且获取数据需要一定的时间

SQL Caching

查询缓存是 Rails 的一个重要的功能;
假如 rails 在同一个请求中遇到了一样的查询, 它将使用缓存的结果; 而不是再去请求一次数据库;

原因是:

数据存储在数据库中, 每一次请求数据库需要读取硬盘, IO 时间较长;
直接读取内存中的数据, 会快很多;

代码案例:

class ProductsController < ApplicationController
  def index
    # 去数据库查询
    @products = Product.all
    # 直接取 内存中的结果
    @products = Product.all
  end
end

注意: 将数据库的数据缓存到内存中, 只存在于一个请求的生命周期中;


如果想要每次获取都取数据库的最新数据, 可以使用ActiveRecord::Base.uncached

ActiveRecord::Base.uncached do
  Post.all.to_a # to_a to force DB query
end

ActiveRecord Relations

rails 的 model association都内置了缓存;

例如: belongs_to, has_one, has_many…
一般情况下, association 的缓存可以提高运行效率. 避免再去数据库中读取数据;

但是, 偶尔也会给我们带来麻烦;

在文档 controlling-caching中有提到的案例:

# 第一次获取, 从数据库中读取
author.books.load

# 之后, 再读取, 直接从内存中读取;
# 此时, 如果数据库的值变化,则会与内存中的不一致
author.books.size

# uses the cached copy of books
author.books.empty?

如果, 我们想要刷新缓存, 重新从数据库中获取最新值.
只需要执行reload即可;

# retrieves books from the database
author.books.load

# uses the cached copy of books
author.books.size

# 如果对应的books有改动, 需要 reload
# discards the cached copy of books and goes back to the database
author.books.reload.empty?

counter_cache

options-for-belongs-to-counter-cache

:counter_cache 是 belongs_to 关系的一个 option.
它可以将所属对象的数量进行缓存;

class Book < ApplicationRecord
  belongs_to :author
end

class Author < ApplicationRecord
  has_many :books
end

上述代码, 如果我们想要知道一个 author 有多少 books 时, 需要执行select count(*)的 sql 语句;

为了避免去数据库查询, 我们可以添加一个 counter_cache

class Book < ApplicationRecord
  # 默认对应的字段名称为 books_count
  belongs_to :author, counter_cache: true
  # 可以指定 count_of_books
  # belongs_to :author, counter_cache: :count_of_books
end

class Author < ApplicationRecord
  # Author 表里需要有一个字段 books_count
  has_many :books
end

上述案例中, 我们需要在Author中添加一个books_count的字段; 也可以指定字段名;

Rails 会在book创建或者不在属于 author 时进行更新;
Rails 会在回调中执行更新 counter, 所以有一些不执行回调的方法, 例如: #delete 则不会更新;

注意: counter_cache 仅能在 belongs_to 下使用;

使用场景:

  • 对实时性要求不高的统计数量; 例如评论数, 关注数

参考文章

 类似资料: