ZAmonk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have a SQLConnection class as defined below:
package SQLConnection; use DBI; use Moose; use MooseX::ClassAttribute; class_has 'dbh' => ( is => 'rw',isa => 'DBI::db', lazy_build => 1 +); class_has 'db' => ( is => 'rw',isa => 'Str', default => 'theDB'); class_has 'port' => ( is => 'rw',isa => 'Int', default => 3306); class_has 'host' => ( is => 'rw',isa => 'Str', default => '127.0.0.1 +'); class_has 'user' => ( is => 'rw',isa => 'Str', default => 'theUSER') +; class_has 'pwd' => ( is => 'rw',isa => 'Str', default => 'thePASS') +; sub _build_dbh { my $self = shift; my $dsn = 'DBI:mysql:'.GSM::SQLConnection->db.';host='.GSM::SQLCon +nection->host.';port='.GSM::SQLConnection->port; return DBI->connect($dsn, GSM::SQLConnection->user, GSM::SQLConnec +tion->pwd); } no Moose; no MooseX::ClassAttribute; __PACKAGE__->meta()->make_immutable(); 1;
Somewhere else, i have a mod_perl handler method called "autocomplete_input" to return values to an autocomplete textbox:
package Neighbouring; use strict; use warnings; use Apache2::Cookie; use Apache2::Request (); use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::RequestUtil (); use Apache::Session::File; use Apache2::Const -compile => qw(OK); use SQLConnection; use JSON; sub handler { my $r = shift; my $req = Apache2::Request->new($r); my $page = $req->param('.state') || 'start'; my $sid; my $j = Apache2::Cookie::Jar->new($r); my $c_in = $j->cookies('nb_session_id'); # get cookie from r +equest headers if (($c_in) && ($page ne 'start')) { # retri +eve existing cookies only if we are not on the start page $sid = $c_in->value; } else { my %session; tie %session, 'Apache::Session::File', undef, { Directory => '/tmp', LockDirectory =>'/tmp', }; $sid = $session{'_session_id'}; my $c_out = Apache2::Cookie->new($r, -name => 'nb_session_id', - +value => $sid, -expires => '+8H'); $c_out->bake($r); # send cookie in response +headers } my $template = Template->new({INCLUDE_PATH => '/template_dir', PRE +_PROCESS => 'config',}); my %states = ( 'start' => \&start_page, 'notfound' => \&notfound_page, 'auto_input' => \&autocomplete_input, ); if ($states{$page}) { $states{$page}->($r,$template,$sid); # call the correct +subroutine } else { $states{'notfound'}->($r,$template,$sid); } } sub autocomplete_input { my ($r,$template,$sid) = @_; my $req = Apache2::Request->new($r); my $cellid = $req->param('query'); $cellid = quotemeta($cellid); my $sth = SQLConnection->dbh->prepare('select distinct LAC,CI,User +Label from Cell where UserLabel like \'%'.$cellid.'%\' order by UserL +abel'); $sth->execute; my @results; while (my @row = $sth->fetchrow_array) { $row[2] =~ s/\"//g; push @results,$row[0].','.$row[1].'/'.$row[2]; } my $ret = {'query' => $cellid, 'suggestions' =>\@results}; $r->content_type('application/json'); $r->no_cache(1); $r->headers_out; print to_json($ret); return Apache2::Const::OK; }
This works fine most of the time, but every now and then i get a DBD::mysql::st execute failed: Lost connection to MySQL server during query at .. in the Apache error log - and the result is that the autocomplete text box is not populated (as no values are returned). So, somehow the MySQL is being sent to digital heaven prematurely. Do you have any idea why? Is this perhaps a side effect of the interaction between the mod_perl handler and the web server? Where else could this error be originaing from? As a work around, i was thinking of using mod_dbd in order to let the Apache server manage the SQL connection. Does anyone have a better idea? (please ignore any obvious syntax errors in the code above)

Replies are listed 'Best First'.
Re: The Moose, dbh class attribute, mod_perl handler and a lost SQL connection
by stvn (Monsignor) on Oct 07, 2009 at 20:27 UTC

    It look that your $dbh is being disconnected (which happens sometimes) and so when you try and call prepare it has no connection and since your SQLConnection class has no logic for handling or detecting this it dies. You might want to take a look at DBIx::Connector for handling your connections with, it is an extraction of the connection handling code from DBIx::Class.

    -stvn
Re: The Moose, dbh class attribute, mod_perl handler and a lost SQL connection
by derby (Abbot) on Oct 07, 2009 at 20:35 UTC

    I hate answering a question that I front-paged but it's been hours with no response ... so here goes ... I would probably change dbh from an attribute to a method and then use DBI::connect_cache. That way you can ensure you have a live connection before attempting to use it.

    class_has 'db' => (is => 'rw',isa => 'Str', default => 'theDB'); class_has 'port' => (is => 'rw',isa => 'Int', default => 3306); class_has 'host' => (is => 'rw',isa => 'Str', default => '127.0.0.1'); class_has 'user' => (is => 'rw',isa => 'Str', default => 'theUSER'); class_has 'pwd' => ( s => 'rw',isa => 'Str', default => 'thePASS'); sub dbh { my $self = shift; my $dsn = 'DBI:mysql:' . GSM::SQLConnection->db . ';host=' . GSM::SQLConnection->host . ';port=' . GSM::SQLConnection->port; return DBI->connect_cached( $dsn, GSM::SQLConnection->user, GSM::SQLConnection->pwd ); } no Moose; no MooseX::ClassAttribute; __PACKAGE__->meta()->make_immutable(); ... my $sth = SQLConnection->dbh()->prepare( ... )

    -derby
      Thank you, i think i'll use both suggestions:
      sub dbh { ... return DBIx::Connector->connect($dsn,...); }
Re: The Moose, dbh class attribute, mod_perl handler and a lost SQL connection
by dsheroh (Monsignor) on Oct 08, 2009 at 07:29 UTC
    It's most likely just a MySQL timeout. The simplest way of dealing with this is to add
    $dbh->{mysql_auto_reconnect} = 1;
    immediately after connecting to the database.