【问题标题】:Alternatives to storing Moose object using Apache::Session with CODE references使用 Apache::Session 和 CODE 引用存储 Moose 对象的替代方法
【发布时间】:2010-06-18 13:08:57
【问题描述】:

我有一个 Moose 类,我想使用 Apache::Session::File 来存储它。

但是,Apache::Session::File 默认情况下不会存储它,而是我收到错误消息:

 (in cleanup) Can't store CODE items at blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\_freeze.al)...

这个问题可以通过设置来规避

$Storable::Deparse = 1;
$Storable::Eval = 1;

为了允许 CODE 引用被序列化。

Moose 类中的违规方法如下所示,该方法从 mysql 数据库中检索列:

sub _build_cell_generic {
    my ($self,$col) = @_;
    my $sth = $self->call_dbh('prepare','select '.$col.' from '.$self->TABLE.' where CI = ? and LAC = ? and IMPORTDATE = ?');
    $sth->execute($self->CI,$self->LAC,$self->IMPORTDATE);
    my $val = $sth->fetchrow_array;
    $sth->finish;
    return defined $val ? $val : undef;
}

所以大概 dbh 对象(即 DBIx::Connector)包含 CODE 引用。

有没有比设置 $Storable::Deparse 和 $Storable::Eval 更好的方法来允许这个 Moose 类的序列化?

以下测试脚本产生错误:

#!/usr/bin/perl -w

use Apache::Session::File;
use Test::More;
use strict;
use warnings;

require_ok( 'GSM::TestCell' );
require_ok( 'GSM::SQLConnection');

my $db = new_ok('GSM::SQLConnection');
my $cell4 = new_ok( 'GSM::TestCell' => [{LAC => 406, CI => 24491, DB => $db }] );

my %session;
tie %session, 'Apache::Session::File', undef, {Directory =>"./", LockDirectory   => "./" };
print "BCCH is ",$cell4->BCCH,"\n";
$session{$cell4->ID} = $cell4;
done_testing();
__END__

SQL连接类定义为:

package GSM::SQLConnection;
#use DBI;
use Moose;
use DBIx::Connector;

has dbixc => (is => 'ro', isa => 'DBIx::Connector', lazy_build => 1, handles => [ qw(dbh) ]); 

sub _build_dbixc {
    my $self = shift;
    my $dsn = 'DBI:mysql:testDB;host=127.0.0.1;port=3306';
    return DBIx::Connector->new($dsn,'user','pwd');
}

sub call_dbh {
    my $self = shift;
    my $method = shift;
    my @args = @_;
    $self->dbixc->run(fixup => sub { $_->$method(@args) });
}
no Moose;
__PACKAGE__->meta->make_immutable;
1;

TestCell 类定义为:

package GSM::TestCell;
use MooseX::NaturalKey;
use strict;
use warnings;

has [qw(LAC CI)] => (is => 'ro', required => 1);
has [qw(ID BCCH IMPORTDATE)] => (is => 'rw', lazy_build => 1);
has 'DB' => (is => 'rw', isa => 'GSM::SQLConnection', required => 1, );
has 'TABLE' => (is => 'rw', default => 'Cell');

primary key =>('LAC','CI');

sub _build_ID {
    my $self = shift;
    return join(',',$self->LAC,$self->CI);
}

sub _build_IMPORTDATE {return '2010-06-21'}

sub _build_BCCH {(shift)->_build_cell_generic('BCCHFrequency');}

sub _build_cell_generic {
    my ($self,$col) = @_;
    my $sth = $self->DB->call_dbh('prepare','select '.$col.' from '.$self->TABLE.' where CI = ? and LAC = ? and IMPORTDATE = ?');
    $sth->execute($self->CI,$self->LAC,$self->IMPORTDATE);
    my $val = $sth->fetchrow_array;
    $sth->finish;
    return defined $val ? $val : undef;
}

no Moose;
__PACKAGE__->meta->make_immutable;
1;

【问题讨论】:

    标签: perl moose storable


    【解决方案1】:

    我真的怀疑你真的需要序列化代码引用;您包含的示例没有。无论如何,您都不想序列化 DBIx::Connector 对象,因为它们只特定于当前运行时实例。

    DBIx::Connector 对象中可能有一个小的 coderef,因为通常会将对 dbh 的访问包装在一个 sub 中以捕获连接消失的情况(参见“修复”的讨论)在 @987654321 @。

    Moose 对象的序列化由MooseX::Storable 处理,易于扩展。您可以在其中自定义一个序列化程序以满足您的需求 - 即选择要序列化的属性和要忽略的属性。

    【讨论】:

    • 附言。我希望你不要为你的每一个 Moose 类创建一个新的 DBIx::Connector 对象;这样你很快就会用完数据库句柄。您应该尽可能多地共享对象以提高您的应用程序的效率。
    • 我稍微扩展了问题描述。我不是为每个 Moose 类创建数据库对象。感谢您的建议:MooseX::Storage 似乎是要走的路。如果我将它与 DB 属性上的 traits => ['DoNotSerialize'] 结合使用,那么我可以序列化对象。有趣的是,如果我将 GSM::SQLConnection 中的 DBIx::Connector impelmentation 替换为使用 DBI 的等效项,那么我不会遇到“无法存储代码项”的问题。
    【解决方案2】:

    Apache::Session::File 使用的 Storable 类的文档使用 $Storable::Deparse 和 $Storable::Eval,但还继续建议了一种用于序列化 CODE 引用和反序列化的方法一个“安全”的隔间。本页的示例部分给出了一个示例:

    http://perldoc.perl.org/Storable.html#CODE-REFERENCES

    【讨论】:

      猜你喜欢
      • 2017-02-26
      • 1970-01-01
      • 2016-04-16
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多