DBIx :: Class是否具有透明缓存?

时间:2009-08-12 18:04:44

标签: perl caching dbix-class

在C#/ .Net世界中,有一些ORM,如NHibernate或ActiveRecord,包括透明缓存:数据库更新透明地复制到缓存,对象在可用时直接从缓存中检索等(通常使用memcached)。

使用DBIx::Class的Perl看起来不像透明缓存。我错过了什么?这似乎是一个普遍的需求,我很惊讶我在CPAN或谷歌上找不到任何东西。

4 个答案:

答案 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安装自动完成了,但我不记得)。

DBIx::Class::ResultSet