2010-06-15 35 views
3

J'ai une application Web basée sur mod_perl2 qui nécessite une connexion à une base de données mysql. J'ai implémenté les spécificités de connexion SQL dans un rôle d'orignal.Trop de connexions DB avec l'application mod_perl2 moose

simplifié, le rôle se présente comme suit:

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; 

J'utilise ensuite ce rôle dans toutes les classes d'orignaux qui nécessitent une connexion à la base de données avec une déclaration

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

.

Bien que cela fonctionne bien lorsque quelques objets sont créés, je rencontre rapidement des problèmes lorsque de nombreux objets sont créés. Dans le journal des httpd par exemple, je reçois l'erreur:

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

Je pensais à l'aide DBIx :: Connecteurs « déconnexion » appel pour fermer la connexion à la base de données à chaque fois, mais l'impact sur les performances semblent graves pour ouvrir/fermer les connexions au besoin.

Avez-vous d'autres suggestions sur ce problème?

Répondre

6

Copiez-vous le dbh et l'utilisez-vous dans des endroits où l'objet DBIx::Connector est hors de portée? La documentation dit spécifiquement de ne pas le faire. Au lieu de cela, enregistrez l'objet DBIx :: Connector lui-même et déléguez-lui l'appel de méthode dbh avec une option handles dans l'attribut.

C'est ce que je fais (En fait, je viens de publier hier code en réponse à une autre question, drôle comment les questions DB viennent en paquets):

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) }); 
} 

Vous pouvez également regarder le nombre de processus mod_perl vous permettez. Chaque processus ou thread séparé doit nécessairement avoir sa propre connexion DB, mais il peut y en avoir plus d'un. Vous devez donc également veiller à ce que le code ci-dessus ne s'exécute que (par exemple un objet de gestion DB). , et chaque tentative ultérieure de construire un tel objet retourne simplement une copie de l'existant. Un moyen facile de le faire est avec MooseX::Singleton, mais cela introduit d'autres problèmes de conception de son propre chef.

+1

Merci, j'aime vraiment ce code, mais il ne résout toujours pas le problème de "Trop de connexions ..". Je suppose que pour le problème en question, la conception appelle autre chose que l'encapsulation de la connexion DB dans un rôle, simplement parce qu'il y a trop d'objets en cours de création. –