8

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

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

4

4 回答 4

6

半透明地有 DBIx::Class::Cursor::Cached (来自 mst,如 DBIC)。不过,您需要为您的连接或模式对象提供一个 Cache 对象。不幸的是,似乎非常无证。

Cookbook 确实有一个在 DBIC 上使用 Tie::Cache 的示例,并且在 DBIx::Class::ResultSet 上也有 (get|set|clear)_cache 函数,但它们可能并不完全符合您的需要。

于 2009-08-12T19:04:45.077 回答
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 表类的基类中执行此类操作,您应该能够非常轻松地构建透明缓存。

于 2009-08-12T19:30:55.880 回答
1

我在基于 DBIx::Class 的模型中遇到了同样的需求,在查看了这里的答案后,我并没有真正看到任何我正在寻找的解决方案。在解决了这个问题之后,我开始认为我的业务层应该处理缓存,因此我将 DBIx::Class 视为不实现业务逻辑的持久层。

例如,我当前具有理想缓存的代码将是这样的:

my $network = SL::Model::App->resultset('Network')->search({ ip => '127.0.0.1' });

$network 对象由我在 DBIx::Class 模式初始化期间配置的 $memcached 缓存提供服务

新代码将是:

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;

}

你明白了。

于 2010-11-05T06:13:53.903 回答
0

我想补充一点,而不是在 中添加“搜索”方法My::Table

还可以增强 提供的 ->search 方法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 提供这种更改(缓存)的搜索,从而将所有表的缓存代码保存在一个地方,恕我直言,这会少很多混乱。

不过,我还没有测试过。

为了使上面的例子工作,把它放在一个文件中,用你的模式类的名称,在目录"../Schema/ResultSet/"中,并确保你的 Schema.pm 包含"load_namespaces();"它将很好地自动加载你放在那里的所有重载类(我认为我的Catalyst install 是自动完成的,但我不记得了)。

DBIx::Class::ResultSet

于 2014-10-31T21:18:37.807 回答