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;
这是正确的方式吗? 在我的代码上重用数据库 而不是必须打开一个新的 连接或将打开 每次使用它时都有一个新的连接
我应该改变什么 模块?或者我做错了什么?
目前我只是在学习并想到自己做引擎模块,所以我从这开始。
简单的测试代码(下面的代码不仅仅是关于如何使用模块的示例):
#!/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;
答案 0 :(得分:3)
我建议使用现有的数据库界面,而不是滚动自己的数据库界面,因为有许多秘密陷阱,其他人已经花了多年时间为你解决和解决问题。 DBIx::Connector非常出色,使用fixup
模式,您可以重复使用数据库连接,甚至可以跨进程分支。
此外,如果使用Moose,则永远不必再次编写自己的对象构造函数或对象字段。 :)
DBIx::Class与Moose相结合会更好,但在你发现自己需要更多ORM-ish功能之前没有必要。
答案 1 :(得分:2)
除了使用CPAN模块完成此任务外,以下是我的实用建议:
如果您班级的用户未启用AutoCommit
,则出于某种原因选择不启用AutoCommit
。因此不要这样做:
unless ($self->{Handle}->{AutoCommit}) {
$self->{Handle}->commit;
}
在DESTROY
。
open
的行为,即使参数不能打开文件也是如此to open
是一个有效的文件名,并通过返回false值来指示这种情况。因此,检查bless
的返回值不起任何作用。如果要处理bless
失败的可能性,则必须捕获致命的运行时异常。答案 2 :(得分:1)
您揭露错误的方式非常非常老式。如果出现异常情况,为什么不提出适当的例外?您似乎已在DBI
模块之后对错误处理进行了建模。请注意,DBI
也有RaiseError
选项。使用它几乎总是比使用旧式errorstr
版本更合理。不幸的是,DBI现在不能再改变它的默认值,但对于新代码,我完全看不出复制这个有缺陷的想法的原因。
您还在代码中构建DBI连接,基于用户从外部提供的参数。你有充分理由这样做吗?允许用户传入他自己构建的DBI::dh
会更灵活。是的,这需要在外部稍微更多的代码来设置对象并将它们连接在一起,但它也将导致更清洁的设计。如果手动连接您的对象太困扰您,您可能需要查看Bread::Board
为您进行布线,而不是牺牲模块的设计。
另外,我第二次提出使用DBIx::Connector
的以太的建议。管理数据库句柄确实需要很多痛苦,这可能非常容易出错。