model级别cache的(一)
上一篇 /
下一篇 2007-11-18 11:37:28
/ 精华(1)
/ 个人分类:projects
查看( 6 ) /
评论( 4 )
数据库是瓶颈,今天我们介绍
model级别的cache。Cached Model 是一个简单的只对单记录做缓存的plugin.Cached Model的的存储分为本地存储和Memcached存储。本地存储大家都知道,一般都是用Hash来存储的。这里的Memcached是一种网络分布式存储。
我们先来看看如果应用cached model
一:安装
CODE:
gem install cached_model -y二:应用
简单的创建一个工程
CODE:
rails cached_model_demo新建Page
CODE:
ruby script/generate scaffold_resource page title:string content:text created_at:timestamp创建数据库
CODE:
rake db:migrate修改Page Model,继承CachedModel
CODE:
class Page < CachedModel
end在enviroment中增加memcached的配置的代码:
CODE:
require 'cached_model'
memcache_options = {
:c_threshold => 10_000,
:compression => true,
:debug => false,
:namespace => 'cached_model_demo',
:readonly => false,
:urlencode => false
}
CACHE = MemCache.new memcache_options
CACHE.servers = 'localhost:11211'上面都是一些简单的东西,我们就忽略了,有什么问题,大家提出来。
好了,准备就绪。cached_model 默认是采用memcached store的方式,当然你可以采用local的方式
CODE:
CachedModel::use_local_cache=true启动memcached server
CODE:
memcached -vv我们传递vv参数可以查看更多的日志信息,具体的可以查看--help
打开ruby script/console 并打开tail -f log/development.log查看日志
新建page
CODE:
Page.create :title=>'Hello World'
Page.create :title=>'Hello World Again'成功。cached_model只覆盖了ActiveRecord的两个方法,一个是find,一个是find_by_sql.我们具体的分析一下这两个方法
1:) find
CODE:
def self.find(*args)
args[0] = args.first.to_i if args.first =~ /\A\d+\Z/
# Only handle simple find requests. If the request was more complicated,
# let the base class handle it, but store the retrieved records in the
# local cache in case we need them later.
if args.length != 1 || !Fixnum === args.first then
# Rails requires multiple levels of indirection to look up a record
# First call super
records = super
# Then, if it was a :all, just return
return records if args.first == :all
return records if RAILS_ENV == 'test'
case records
when Array then
records.each { |r| r.cache_store }
end
return records
end
return super
end这里面压根没有读取cache的代码,不管这么样,都会先调用super执行查询,只有在
>参数个数不为1或第一个不是数字
>第一个参数不是:all
>不是test环境下
>返回结果为Array的时候才缓存model
也就是说基本没什么作用。
我们试验下
CODE:
Page.find 1依然执行SQL,memcached无反应
CODE:
Page.find 1,2我们会看到memcached中有了两条记录
CODE:
<1924 new client connection
<1924 set cached_model_demo:active_record:Page:1 0 900 95
>1924 STORED
<1924 set cached_model_demo:active_record:Page:2 0 900 101
>1924 STORED保存了两条记录
在执行
CODE:
Page.find 1依然查询数据库。那我们该如何取这样的数据呢?
CODE:
>> Cache.get "active_record:Page:1"
=> #"Hello World", "id"=>"1", "content"=>nil, "cr
ed_at"=>"2007-11-10 18:29:29"}>2:)find_by_sql
CODE:
def self.find_by_sql(*args)
return super unless args.first =~ /^SELECT \* FROM #{table_name} WHERE \(?#{table_name}\.#{primary_key} = '?(\d+)'?\)? +LIMIT 1/很简单,但是他只cache根据主键id查询的record
CODE:
Page.find_by_sql "SELECT * FROM PAGES WHERE PAGES.ID = 1 LIMIT 1"CODE:
<1924 get cached_model_demo:active_record:Page:1
>1924 sending key cached_model_demo:active_record:Page:1
>1924 ENDdevelopment.log无SQL查询
CODE:
MemCache Get (0.000000) active_record:Page:1这里取回的是我们刚才执行Page.find 1,2,缓存1的数据,如果没有,则会存储该数据,下次再查询直接从cache中获取。
三:更新
当该id的记录update,destroy都会更新cache,这个没什么好说的。
四:改进
这些功能太过于简单了,我们可以稍微对源码做点修改
一:缓存Page.find 的单条记录
CODE:
if CachedModel.use_memcache?
record = Cache.get "active_record:#{name}:#{args.first}"
#return cached model
return record unless record.nil?
#call super find
record = super
#store in memcache
record.cache_store
return record
end
end二:find_by_sql的改进,空格,大小写必须一致才能生效
这条
正则表达式太过于简单,我们可以稍微修改
1:) 忽略大小写 /i
2:) 忽略table的名称,只需要id=?几匹配
2;) 忽略空格
警告:
对于有关联的Model请谨慎使用cached_model,建议不使用。
[
本帖最后由 martin 于 2007-11-12 09:38 编辑]
论坛模式
推荐
收藏
分享给好友
推荐到圈子
管理
TAG:
-
axgle发布于2007-11-16 11:54:45
-
本文有没有必要放到还没有开设的新版"高级编程"里?
"高级编程":Ruby/Rails高级编程 面向对象设计 性能优化,企业级应用等.
-
drive2me
发布于2007-11-16 15:34:30
-
收藏了,哈哈!谢谢2位高手!
-
bayerlin
发布于2007-11-18 01:32:42
-
谢谢楼主,提供了这么好的ruby
-
blackanger
发布于2007-11-24 17:10:07
-
文章不错。但是这最后的警告:
“对于有关联的Model请谨慎使用cached_model,建议不使用。”
一般还是有关联的model多啊。。。