在Perl中创建数据库模块

时间:2014-08-03 12:48:30

标签: perl perl-module dbi

我想知道这是否是创建数据库模块的正确方法,尤其是创建和使用数据库句柄的方式:

use strict;
use warnings;
use DBI;

my $DB_NAME = 'dancerapp';
my $DB_USER = 'root';
my $DB_PASS = 'root';

sub new {
    my $class = shift;
    return {}, $class;
}

sub _connect { #use connect_cached() instead?
    my $dbh = DBI->connect($DSN, $DB_USER, $DB_PASS) or die $DBI::errstr;
    return $dbh;
}

sub getTickets {
    my $self = shift;
    my $ticket_holder = shift;
    my $dbh = $self->_connect;
    my $sth = $dbh->prepare("SELECT * FROM table WHERE assigned_to=?");
    $sth->execute($ticket_holder);
    return $sth->fetchall_hashref;
}

1;

将所有数据库查询存储在一个模块中的主要目的是为它们提供一个单独的位置,我只关心有多个连接/数据库句柄随处可见

2 个答案:

答案 0 :(得分:2)

在Perl传统中,有很多方法可以做到这一点。但我会尽可能多地将一次性操作移动到构造函数中。

您的代码存在一些特定问题

  • 您需要模块的包(类)名称

  • 您的构造函数需要bless哈希引用,而不仅仅是return

  • 您没有定义$DSN

  • 您的getTickets方法无法使用$dbh。在调用DBI->connect

  • 时,句柄应存储在对象中

除此之外,我认为没有理由采用单独的connect方法。这是你可以进入构造函数方法

的东西

每次要执行查询时,重复调用prepare也没有意义。相反,使用||=缓存语句以节省经常使用的查询的处理时间。

最后,最好将DB名称,用户和传递作为参数传递给new。这样,您可以将同一模块用于多个数据库,而无需编辑模块来更改环境。

这就像我要写的那样。请注意,除了确保编译之外,它还没有经过测试。使用它一段时间之后,您可能会发现想要将更多信息移动到对象中 - 例如DSN - 只是为了帮助调试。

package MyDB;

use strict;
use warnings;

use DBI;

sub new {
    my $class = shift;

    my $self = {};
    @{$self}{qw/ db user pass /} = @_;

    my $dsn = "DBI:mysql:database=$self->{db}";
    $self->{dbh} = DBI->connect($dsn, @{$self}{qw/ user pass /}) or die $DBI::errstr;

    bless $self, $class;
}

sub get_tickets {
    my $self = shift;
    my ($ticket_holder) = @_;

    $self->{get_tickets} ||= $self->{dbh}->prepare('SELECT * FROM table WHERE assigned_to = ?');
    $self->{get_tickets}->execute($ticket_holder);

    $self->{get_tickets}->fetchall_hashref;
}

1;

答案 1 :(得分:1)

创建数据库模块没有绝对的“正确方法”。你的方式似乎是一个很好的起点,特别是如果它以当前的形状为你工作,但你可能需要根据自己的需要进行一些迭代来优化模块及其功能。

如果我可以提供一些自以为是的指示:

  • 拥有一个用于处理数据库连接的参考模块是一个好主意。如果您需要广泛采用,请尽可能轻松地使用“开箱即用”。你不希望发生“XKCD: Standards”的情况。

  • 在单个模块中进行所有数据库查询也有一些优点,但是根据您需求增长的程度,您很快就会得到一个难以维护的数千行怪物。因此,从get get中对较小的子模块进行排序/分类可能会让您免于痛苦。

  • 进一步推送上一条评论,如果查询与系统某些对象的行为直接相关,请考虑使用DBIx::Class之类的ORM。

  • 将配置(DSN,用户名,密码)与模块分开。这对于不小心测试生产实例的前沿开发特别有用。

  • 使用一组专用的显式参数传递给DBI和底层驱动程序(例如AutoCommmit => 0),可选择允许用户覆盖一些。

  • 如果您的DBMS支持事务,请确保您的模块不会通过始终提交或回滚它们来避免松散事务。或者,您可以让用户负责显式使用提交或回滚,如果他们不这样做,die()真的很难。当许多其他并发模块使用数据库时,这将为您节省很多痛苦。

  • connect_cache()有优点,但它可能会带来一系列并发问题。

此外,如果您的模块旨在用于Web应用程序,请注意Apache::DBI可能会因您的连接方式而自由。