在C#/ .Net世界中,有一些ORM,如NHibernate或ActiveRecord,包括透明缓存:数据库更新透明地复制到缓存,对象在可用时直接从缓存中检索等(通常使用memcached)。
使用DBIx::Class的Perl看起来不像透明缓存。我错过了什么?这似乎是一个普遍的需求,我很惊讶我在CPAN或谷歌上找不到任何东西。
答案 0 :(得分:6)
半透明地有DBIx :: Class :: Cursor :: Cached(来自mst,如DBIC)。您需要为连接或模式对象提供Cache对象。遗憾的是,似乎没有证据。
Cookbook确实有一个在DBIC上使用Tie :: Cache的例子,在DBIx :: Class :: ResultSet上也有(get | set | clear)_cache函数,但它们可能不是你需要的
答案 1 :(得分:5)
这是一种可以使用CHI添加缓存的简单方法。我实际上没有尝试过这个,所以可能有一些我没有考虑过的陷阱,特别是关于DBIC结果集的序列化。
package My::Table;
use strict;
use warnings;
use base 'DBIx::Class';
use Storable 'freeze';
use CHI;
$Storable::canonical = 1;
__PACKAGE__->load_components(qw/Core/);
__PACKAGE__->table('mytable');
# ....
my $CACHE = CHI->new( driver => 'Memory' );
sub search {
my $self = shift;
my $key = freeze( \@_ ); # make cache key from params
if ( my $rs = $CACHE->get( $key ) ) {
return $rs;
}
# Note: there are issues with context propagation here
my $rs = $self->next::method( @_ );
$CACHE->set( $key => $rs );
return $rs;
}
sub update {
my $self = shift;
my @keys = $self->find_all_cache_items_affected_by_this_update( @_ );
$CACHE->remove( $_ ) for @keys;
$self->next::method( @_ );
}
这有点笨拙,但我认为这是一个很好的起点。如果您在所有DBIx :: Class表类的基类中执行此类操作,则应该能够非常轻松地构建透明缓存。
答案 2 :(得分:1)
我在基于DBIx :: Class的模型中遇到了同样的需求,在查看了答案后,我并没有真正看到任何我正在寻找的解决方案。在努力解决这个问题之后,我开始认为我的业务层应该处理缓存,因此我将DBIx :: Class视为不实现业务逻辑的持久层。
例如,我目前使用理想缓存的代码是这样的:
my $network = SL::Model::App->resultset('Network')->search({ ip => '127.0.0.1' });
$ network对象是从我配置的$ memcached缓存中提供的 DBIx ::类架构初始化
新代码将是:
my $network = SL::Network->find_by_ip_or_create({ ip => '127.0.0.1' });
同时,在附近的模块中:
package SL::Network;
...
use SL::Model::App;
use SL::Cache;
our $cache = SL::Cache->new;
sub find_by_ip_or_create {
my ($class, $args) = @_;
my $network;
unless ($network = $cache->get('network|' . $args->{ip}) {
$network = SL::Model::App->resultset('Network')->find_or_create({ wan_ip => $args->{ip}});
$cache->set('network|' . $args->{ip} => DBIx::Class::Schema->freeze($network));
}
return $network;
}
你明白了。
答案 3 :(得分:0)
我想补充一点,而不是在My::Table
中添加“搜索”方法,
还可以增强DBIx::Class::ResultSet
提供的 - >搜索方法,如下所示:
package Schema::ResultSet::My::Table;
use base 'DBIx::Class::ResultSet';
sub search {
my ( $self, $args ) = ( shift, shift );
# do what you want here with the args passed to ->search
return $self->next::method( $args, @_ );
}
此外,您很可能是ResultSet的子类,因此您可以将此更改(缓存)搜索提供给所有ResultSet,从而将缓存代码保存在所有表的一个位置, 这将是一个不那么混乱的imho。
但我还没有测试过。
要使上面的示例正常工作,请将其放在具有架构类名称的文件中,放在目录"../Schema/ResultSet/"
中,并确保您的Schema.pm包含"load_namespaces();"
,这将很好地自动执行加载你放在那里的所有重载类(我认为我的Catalyst安装自动完成了,但我不记得)。