views:

455

answers:

3

In the C#/.Net world, there are ORMs such as NHibernate or ActiveRecord that includes transparent caching: database updates are transparently replicated to the cache, objects are retrieved directly from the cache when available, etc (often with memcached).

It doesn't look like transparent caching is available in Perl with DBIx::Class. Did I miss something? That seems like a common need, I'm surprised I couldn't find anything on it on CPAN or Google.

+4  A: 

Semi-transparently there is DBIx::Class::Cursor::Cached (from mst, like DBIC). You need to provide a Cache object to your connections or schema objects though. Seems very undocumented unfortunately.

The Cookbook does have an example for using Tie::Cache on DBIC, and there are also the (get|set|clear)_cache functions on DBIx::Class::ResultSet, but they are probably not exactly what you need.

MkV
From what I understood, this is caching for a very limited use case. if you do a search, and go over the items in your search several times, you can cache the result set. But you can not cache individual objects. I've tested it, in my case it does not help at all (I actually get worse performances because I cache the search result, but use it once only)
Julien
Actually, it could be a solution. The problem is with relationships: the main resultset is cached, but not the relationships.
Julien
+3  A: 

Here's a simple way that you could add caching with CHI. I haven't actually tried this, so there may be pitfalls I haven't considered, especially with regard to the serialization of DBIC result sets.

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( @_ );
}

It's a bit clunky, but I think it's a good starting point. If you do this type of thing in a base class for all your DBIx::Class table classes, you should be able to build in transparent caching pretty easily.

friedo
Thanks, it looks like the way to go. I'm using Catalyst with Catalyst::Model::DBIC::Schema and I count not find the right place to override the search method for example: I tried in the DBIx::lass, and in DBIx::Class::Schema, but using $c->model(''')->search does not use the new search method
Julien