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

发布于 2024-09-26 05:41:49 字数 3503 浏览 4 评论 0原文

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. 我应该改变什么吗? 模块 ?或者我做错了什么?

目前我正在学习并考虑做我自己的引擎模块,所以我从这个开始。

简单的测试代码(以下代码不予审查,只是一个如何使用该模块的示例):

#!/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;
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. Is that the right way so i can
    re-use the database on my code
    instead of having to open a new
    connection or that will aswell open
    a new connection every time i use it
    ?

  2. Should i change anything on the
    module ? or anything i did wrong ?

Currently i am just learning and thinked of doing my own engine module so i began with this.

Simple test code (the bellow code is not to be reviewed just a sample on how to use the module):

#!/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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自由如风 2024-10-03 05:41:49

我建议使用现有的数据库接口,而不是自己开发,因为有许多秘密问题是其他人花了数年时间才为您找出并解决的。 DBIx::Connector 非常出色,并且具有其修复 模式,将允许您重用数据库连接,甚至跨进程分支。

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

DBIx::Class 与 Moose 结合会更好,但不是必需的直到您发现自己需要更多 ORM 风格的功能。

I would suggest using an existing database interface rather than rolling your own, as there are many secret gotchas that others have spent years figuring out and solving for you. DBIx::Connector is excellent, and with its fixup mode, will let you reuse database connections, even across process forks.

Additionally, if you use Moose you will never have to write your own object constructors or object fields again. :)

DBIx::Class combined with Moose would be even better, but not necessary until you find yourself needing more ORM-ish features.

笨笨の傻瓜 2024-10-03 05:41:49

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

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

    unless ($self->{Handle}->{AutoCommit}) {
        $self->{句柄}->提交;
    }
    

    DESTROY中。

  4. 请注意,只要给予可修改的引用, bless 就不会失败(比较例如,open 的行为可能无法打开文件,即使 open 的参数是有效的文件名,并且会通过返回错误值来指示这种情况)。因此,检查bless的返回值没有任何用处。如果您想处理 bless 失败的可能性,则必须捕获致命的运行时异常。

Other than using a CPAN module to accomplish this task, here are my practical recommendations:

  1. Don't return an error value from the constructor. Instead, throw an exception.
  2. Access the internals of your class using accessors rather than using direct hash access.
  3. If the user of your class did not enable AutoCommit, she chose not to enable AutoCommit for a reason. Therefore don't do:

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

    in DESTROY.

  4. Note that bless is not going to fail so long as it is given a modifiable reference (compare this to, say, the behavior of open which can fail to open a file even though the argument to open is a valid filename and would indicate this situation by returning a false value). Therefore, checking the return value of bless does not serve any useful purpose. If you want to handle the possibility of bless failing, you will have to catch fatal runtime exceptions.
樱娆 2024-10-03 05:41:49

你暴露错误的方式非常非常过时。如果发生异常情况,为什么不提出适当的异常呢?您似乎已经在 DBI 模块之后对错误处理进行了建模。请注意,DBI 还有一个 RaiseError 选项。使用它几乎总是比使用老式的 errorstr 版本更合理。不幸的是,DBI 现在无法再更改它的默认值,但对于新代码,我完全不认为有理由复制这个有缺陷的想法。

您还可以根据用户从外部提供的参数在代码中构建 DBI 连接。你有充分的理由这样做吗?允许用户传入自己构造的DBI::dh会更加灵活。是的,这需要更多的外部代码来设置对象并将它们连接在一起,但它也会带来更简洁的设计。如果手动连接对象对您来说太麻烦,您可能需要看看 Bread::Board 为您进行接线,而不是影响模块的设计。

另外,我赞同 Ether 使用 DBIx::Connector 的建议。管理数据库句柄确实很麻烦,而且很容易出错。

Your way of exposing errors is very, very oldfashioned. If something exceptional happens, why not raise a proper exception? You seem to have modelled your error handling after the DBI module. Note that DBI also has a RaiseError option. Using that is almost always more reasonable than using the oldfashioned errorstr version. Unfortunately DBI can't change it's default anymore now, but for new code I entirely don't see the reason to copy this flawed idea.

You're also constructing a DBI connection within your code, based on parameters the user provided from the outside. Do you have a good reason for doing that? Allowing the user to pass in the DBI::dh he constructed himself would be more flexible. Yes, that requires slightly more code on the outside to set up objects and wire them together, but it will also result in a cleaner design. If wiring up your objects manually bothers you too much, you might want to have a look at Bread::Board to do the wiring for you instead of compromising on the design of your module.

Also, I second Ether's suggestion of using DBIx::Connector. It really takes a lot of pain out of managing database handles, which can be very error-prone.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文