2010-06-15 4 views
3

У меня есть веб-приложение на основе mod_perl2, для которого требуется подключение к базе данных mysql. Я применил спецификацию SQL-соединения в роли лося.Слишком много соединений с DB с mod_perl2 лосиным приложением

Упрощенная роль выглядит следующим образом:

package Project::Role::SQLConnection; 

use Moose::Role; 
use DBIx::Connector; 

has 'connection' => (is => 'rw', lazy_build => 1); 
has 'dbh' => (is => 'rw', lazy_build => 1); 
has 'db' => (is => 'rw', default => 'alcatelRSA'); 
has 'port' => (is => 'rw', default => 3306); 
has 'host' => (is => 'rw', default => '10.125.1.21'); 
has 'user' => (is => 'rw', default => 'tools'); 
has 'pwd' => (is => 'rw', default => 'alcatel'); 


#make sure connection is still alive... 
before dbh => sub { 
    my $self = shift; 
    $self->connection->run(fixup => sub { $_->do('show tables') }); 
}; 

sub _build_dbh { 
    my $self = shift; 
    return $self->connection->dbh; 
} 

sub _build_connection { 
    my $self = shift; 
    my $dsn = 'DBI:mysql:'.$self->db.';host='.$self->host.';port='.$self->port; 
    my $conn = DBIx::Connector->new($dsn, $self->user, $self->pwd); 
    return $conn; 
} 

no Moose::Role; 
1; 

Затем я использую эту роль во всех лосей классов, которые требуют подключения к БД с

with qw(Project::Role::SQLConnection); 

заявление.

Хотя это хорошо работает, когда создается несколько объектов, я вскоре сталкиваюсь с проблемами, когда создается множество объектов. В журнале HTTPd, например, я получаю сообщение об ошибке:

DBI connect('alcatelRSA;host=10.125.1.21;port=3306','tools',...) failed: Too many connections at C:/Perl/site/lib/DBIx/Connector.pm line 30

Я думал об использовании DBIx «разъединение» :: Разъемы называют, чтобы закрыть соединение с базой данных каждый раз, но влияние на производительность, кажется серьезным, чтобы открыть/закрыть соединения по мере необходимости.

Есть ли альтернативные предложения по этой проблеме?

ответ

6

Вы копируете dbh и используете его в местах, когда из объекта DBIx::Connector выходит за рамки? В документации конкретно говорится, что этого не делать. Вместо этого сохраните сам объект DBIx :: Connector и делегируйте вызов метода dbh ему с опцией handles в атрибуте.

Это то, что я делаю (я на самом деле просто разместил этот код вчера в ответ на другой вопрос, смешно, как DB вопросы входят в пакеты):

has dbixc => (
    is => 'ro', isa => 'DBIx::Connector', 
    lazy_build => 1, 
    # DO NOT save a copy of the dbh. Use this accessor every time, as 
    # sometimes it will change unexpectedly! 
    handles => [ qw(dbh) ], 
); 

sub _build_dbixc 
{ 
    my $this = shift; 
    DBIx::Connector->new(
     $this->dsn, 
     $this->username, 
     $this->password, 
     $this->connect_options, 
    ); 
} 

sub call_dbh 
{ 
    my $this = shift; 
    my $method = shift; 
    my @args = @_; 

    # the normal behaviour -- pings on every dbh access 
    #return $this->dbh->$method(@args); 

    # the smart behaviour -- presume the DB connection still works 
    $this->dbixc->run(fixup => sub { $_->$method(@args) }); 
} 

Вы также можете посмотреть на то, как много процессов mod_perl вы разрешаете. Каждый отдельный процесс или поток обязательно должен иметь свое собственное соединение с БД, но может быть больше одного - так что вам, вероятно, также необходимо убедиться, что только вышеописанный код (т. Е. Объект управления db) только один раз за процесс , и каждая последующая попытка построить такой объект просто возвращает копию существующего. Один простой способ сделать это - MooseX::Singleton, но это представляет другие проблемы дизайна самостоятельно.

+1

Спасибо, мне очень нравится этот код, но он по-прежнему не решает проблему «Слишком много соединений ..». Я подозреваю, что для рассматриваемой проблемы дизайн требует чего-то другого, кроме инкапсулирования соединения БД в роли, просто потому, что создается слишком много объектов. –