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

Hi all,
During my praying to the Wall, i encountered the following...

We used a DBH class, that returned a DBI connection to a MySQL database. It used the @EXPORT_OK = qw(&DBOBJ); so the object could be accessed using the singleton pattern... BUT...
The MySQL server runned away sometimes, leaving us with a big error screen instead of results...
Then we tried to use APACHE::DBI's ping, to see if the connection was still there, and it was???? This would be magic, but we found out, that this was the penalty of trying to make an object that had a persistent database connection, and even believed this when the MySQL server runned away...
This is checkable by just restarting the MySQL server to emulate the effect.

For now, we're not using Apache::DBI anymore, but built our own (using DBI's source as a guide) so our ping is working again, even with a persistent connection. (when the ping fails, we rebuild the connection
However, i refuse to believe that this would be the only (and best) solution, and think that Apache::DBI could do more for us, i'd use to think that Apache::DBI would handle all connections for us.
Any thoughts on how to enlighten our path again would be welcome.

Replies are listed 'Best First'.
Re: Singletons, Apache::DBI and MySQL
by johnnywang (Priest) on Jan 03, 2005 at 07:45 UTC
    Since you're using mod_perl's Apache::DBI, I don't see any reason for trying to store a persistent connection in your class. Apache::DBI already provides a persistent connection pool. I have the same setup as you(apache/mod_perl/mysql), I have one module that exports a function get_connection(), in all my other scripts I simply call get_connection(). The extra work you are doing won't be more efficient than that.
      The reason i did this is the following:
      use strict; use DBH qw(&DBHOBJ); my $sth = DBHOBJ()->prepare('select blah from table;'); $sth->execute();
      Now the 'OLD' DBH just used Apche::DBI to return $self->{dbh};
      However, the MySQL server sometimes? coused the error "MySQL server has run away'.
      It was not able to reconnect, and the Apache::DBI module returned 1 on the implemented ping-method.
Re: Singletons, Apache::DBI and MySQL
by Thilosophy (Curate) on Jan 03, 2005 at 08:12 UTC
    What you describe sounds like a bug in Apache::DBI's ping(). If that is the case, you should try to get it fixed. Did you contact the Apache::DBI guys?

    For now, we're not using Apache::DBI anymore, but built our own (using DBI's source as a guide) so our ping is working again, even with a persistent connection.

    In the mean-time, you could just "patch" Apache::DBI to use your version of ping.

    Update: Maybe Apache::DBI is not at fault here, since DBD::mysql is responsible for making ping() work. But do ask the Apache::DBI guys about this, they should know.

      I'm not sure if it's a bug in Apache::DBI. the code i used is rather simple, but maybe wrong
      package DBH; use strict; use DBI; @ISA = qw(Exporter); @EXPORT_OK = qw(&DBHOBJ); my $dbhobject = new(); sub new { my $classname = shift; my $self={}; if ($dbhobject) { $self=$dbhobject } else { $self = bless {}; my $dbh = DBI->connect("DBI:mysql:blah) or die DBI::errstr; $self->{"dbh"} = $dbh; } $self; } sub DBHOBJ { return $dbhobject->{"dbh"}; } sub DESTROY { my $self=shift; if ($dbhobject) { $dbhobject = undef; } }
      Then i can call it using:
      use strict; use DBH qw(&DBHOBJ); my $sth = DBHOBJ()->prepare('select blah from table;'); $sth->execute();
        So you are not using any kind of ping at all now? And this works? If you just want to turn off ping completely, I think Apache::DBI has an option for this. But was not your problem that the connection broke and you wanted automatic reconnects? Your code does not seem to do that.
        sub DESTROY { my $self=shift; if ($dbhobject) { $dbhobject = undef; } }
        I doubt that this DESTROY method is called ever. Your $dbhobject is not a blessed reference (just a plain hash ref containing the DBI handle), so this is not really OOP and $classname, $self and so on are a little confusing.

        Update: Okay, maybe I misunderstood. This is the old code you were using (with Apache::DBI)? And it did not reconnect? If so, you were not using Apache::DBI correctly. You have to use "connect" to get a connection, and Apache::DBI will either make a really new connection or just return an alreay open connection. That is transparent to you. What you cannot do is cache the connection Apache::DBI give you in your own singleton object. You have to "connect" every time you want a connection: So instead of

        sub new { my $classname = shift; my $self={}; if ($dbhobject) { $self=$dbhobject } else { $self = bless {}; my $dbh = DBI->connect("DBI:mysql:blah) or die DBI::errstr; $self->{"dbh"} = $dbh; } $self; } sub DBHOBJ { return $dbhobject->{"dbh"}; }
        use
        use Apache::DBI; sub DBHOBJ { DBI->connect("DBI:mysql:blah) or die DBI::errstr; }