Write Through and Read Through caching library inspired by CacheMoney and cache_fu, support ActiveRecord 4, 5 and 6.
SecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support ActiveRecord 4, ActiveRecord 5 and ActiveRecord 6.
Read-Through: Queries by ID, like current_user.articles.find(params[:id])
, will first look in cache store and then look in the database for the results of that query. If there is a cache miss, it will populate the cache.
Write-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.
In your gem file:
ActiveRecord 7
gem 'second_level_cache', '~> 2.7'
ActiveRecord 5.2 and 6.0:
gem 'second_level_cache', '~> 2.6.3'
ActiveRecord 5.0.x, 5.1.x:
gem 'second_level_cache', '~> 2.3.0'
For ActiveRecord 4:
gem "second_level_cache", "~> 2.1.9"
For ActiveRecord 3:
gem "second_level_cache", "~> 1.6"
For example, cache User objects:
class User < ActiveRecord::Base
second_level_cache expires_in: 1.week
end
Then it will fetch cached object in this situations:
User.find(1)
user.articles.find(1)
User.where(status: 1).find(1)
User.where(id: 1).first # or .last
article.user
Cache key:
user = User.find(1)
user.second_level_cache_key # We will get the key looks like "slc/user/1/0"
Expires cache:
user = User.find(1)
user.expire_second_level_cache
or expires cache using class method:
User.expire_second_level_cache(1)
Disable SecondLevelCache:
User.without_second_level_cache do
user = User.find(1)
# ...
end
Only SELECT *
query will be cached:
# this query will NOT be cached
User.select("id, name").find(1)
User.where("name = 'Hooopo'").find(1)
WILL NOT work.# user and account's write_second_level_cache operation will invoke after the logger.
ActiveRecord::Base.transaction do
user.save
account.save
Rails.logger.info "info"
end # <- Cache write
# if you want to do something after user and account's write_second_level_cache operation, do this way:
ActiveRecord::Base.transaction do
user.save
account.save
end # <- Cache write
Rails.logger.info "info"
:truncation
:DatabaseCleaner.strategy = :truncation
In production env, we recommend to use Dalli as Rails cache store.
config.cache_store = [:dalli_store, APP_CONFIG["memcached_host"], { namespace: "ns", compress: true }]
cache_key_prefix
(default: slc
):SecondLevelCache.configure.cache_key_prefix = "slc1"
version
option like this:class User < ActiveRecord::Base
second_level_cache version: 2, expires_in: 1.week
end
# this will fetch from cache
user = User.fetch_by_uniq_keys(nick_name: "hooopo")
post = Post.fetch_by_uniq_keys(user_id: 2, slug: "foo")
# this also fetch from cache
user = User.fetch_by_uniq_keys!(nick_name: "hooopo") # this will raise `ActiveRecord::RecordNotFound` Exception when nick name not exists.
IN
query into a Rails.cache.multi_read operation. For example:Answer.includes(:question).limit(10).order("id DESC").each{|answer| answer.question.title}
Answer Load (0.2ms) SELECT `answers`.* FROM `answers` ORDER BY id DESC LIMIT 10 # Only one SQL query and one Rails.cache.read_multi fetching operation.
Details for read_multi feature.
MIT License