反馈,关于我的模块的问题以及我是否应该更改任何内容?

时间:2010-10-05 23:02:14

标签: perl perl-module feedback

package My::Module;

# $Id$

use strict;
use Carp;
use Data::Dumper;
use DBI;

$My::Module::VERSION  = '0.1';

sub new {
    my ($class, %opt) = @_;
    my $opt_count = keys %opt;

    $class->set_error('');
    #return $class->set_error("Too many arguments to initialize.") if ($opt_count > 5);
    #return $class->set_error("Missing arguments to initialize.") if ($opt_count < 2);

    my $self = bless {
                      _DRIVER_OPTIONS  => $opt{'mysql'},
                     },$class;

    if (not defined $self) {
        return $class->set_error( "new() failed: " . $class->errstr );
    }

    if ($self->{_DRIVER_OPTIONS}->{Host} ne '') {
        $self->{_DRIVER_OPTIONS}->{DataSource} = 'DBI:mysql:database=' . $self->{_DRIVER_OPTIONS}->{Database} . ';host=' . $self->{_DRIVER_OPTIONS}->{Host};
    } else {
        $self->{_DRIVER_OPTIONS}->{DataSource} = 'DBI:mysql:database=' . $self->{_DRIVER_OPTIONS}->{Database} . ';';
    }
    $self->{Handle} = DBI->connect($self->{_DRIVER_OPTIONS}->{DataSource},
                                   $self->{_DRIVER_OPTIONS}->{Username},
                                   $self->{_DRIVER_OPTIONS}->{Password},
                                   { RaiseError=>1, PrintError=>1, AutoCommit=>1 }
                                  );
    return $self->set_error("new(): couldn't connect to database: " . DBI->errstr) unless ($self->{Handle});
    $self->{_disconnect} = 1;

    print Dumper \$self;

    return $self;
}

sub database {
    my $self = shift;
    if (@_) { $self->{Handle} = shift }
    return $self->{Handle};
}

sub set_error {
    my $class   = shift;
    my $message = shift;
    $class = ref($class) || $class;
    no strict 'refs';
    ${ "$class\::errstr" } = sprintf($message || "", @_);
    return;
}

*error = \&errstr;
sub errstr {
    my $class = shift;
    $class = ref( $class ) || $class;

    no strict 'refs';
    return ${ "$class\::errstr" } || '';
}

sub DESTROY {
    my $self = shift;

    unless (defined $self->{Handle} && $self->{Handle}->ping) {
        $self->set_error(__PACKAGE__ . '::DESTROY(). Database handle has gone away');
        return;
    }

    unless ($self->{Handle}->{AutoCommit}) {
        $self->{Handle}->commit;
    }

    if ($self->{_disconnect}) {
        $self->{Handle}->disconnect;
    }
}

1;
  1. 这是正确的方式吗? 在我的代码上重用数据库 而不是必须打开一个新的 连接或将打开 每次使用它时都有一个新的连接

  2. 我应该改变什么 模块?或者我做错了什么?

  3. 目前我只是在学习并想到自己做引擎模块,所以我从这开始。

    简单的测试代码(下面的代码不仅仅是关于如何使用模块的示例):

    #!/usr/bin/perl
    
    use warnings;
    use strict;
    use Data::Dumper;
    use lib 'path to module';
    use My::Module;
    
    my $session = My::Module->new(mysql     => {
                                                Database =>'module',
                                                Host     =>'10.0.0.2',
                                                Username =>'module',
                                                Password =>'module'
                                               }) or die My::Module->errstr;
    
    my $dbh = $session->database();
    my $sth = $dbh->prepare(q{
                 SELECT session_id
                 FROM sessions
              });
       $sth->execute() || die print($dbh->errstr);
    my $ref = $sth->fetchall_arrayref({});
    $sth->finish;
    
    print Dumper \$ref;
    

3 个答案:

答案 0 :(得分:3)

我建议使用现有的数据库界面,而不是滚动自己的数据库界面,因为有许多秘密陷阱,其他人已经花了多年时间为你解决和解决问题。 DBIx::Connector非常出色,使用fixup模式,您可以重复使用数据库连接,甚至可以跨进程分支。

此外,如果使用Moose,则永远不必再次编写自己的对象构造函数或对象字段。 :)

DBIx::Class与Moose相结合会更好,但在你发现自己需要更多ORM-ish功能之前没有必要。

答案 1 :(得分:2)

除了使用CPAN模块完成此任务外,以下是我的实用建议:

  1. 不要从构造函数返回错误值。相反,抛出异常。
  2. 使用访问器访问类的内部,而不是使用直接哈希访问。
  3. 如果您班级的用户未启用AutoCommit,则出于某种原因选择不启用AutoCommit。因此不要这样做:

    unless ($self->{Handle}->{AutoCommit}) {
        $self->{Handle}->commit;
    }
    

    DESTROY

  4. 请注意bless只要给出一个可修改的引用就不会失败(比较一下open的行为,即使参数不能打开文件也是如此to open是一个有效的文件名,并通过返回false值来指示这种情况。因此,检查bless的返回值不起任何作用。如果要处理bless失败的可能性,则必须捕获致命的运行时异常。

答案 2 :(得分:1)

您揭露错误的方式非常非常老式。如果出现异常情况,为什么不提出适当的例外?您似乎已在DBI模块之后对错误处理进行了建模。请注意,DBI也有RaiseError选项。使用它几乎总是比使用旧式errorstr版本更合理。不幸的是,DBI现在不能再改变它的默认值,但对于新代码,我完全看不出复制这个有缺陷的想法的原因。

您还在代码中构建DBI连接,基于用户从外部提供的参数。你有充分理由这样做吗?允许用户传入他自己构建的DBI::dh会更灵活。是的,这需要在外部稍微更多的代码来设置对象并将它们连接在一起,但它也将导致更清洁的设计。如果手动连接您的对象太困扰您,您可能需要查看Bread::Board为您进行布线,而不是牺牲模块的设计。

另外,我第二次提出使用DBIx::Connector的以太的建议。管理数据库句柄确实需要很多痛苦,这可能非常容易出错。