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

I had a solution for this (see below), but now realize it is flawed. In a set of modules that manage persistent objects stored in a SQL database, what is a good way to manage the database connections? Goals would be: (1) have a single place in the code where all connections are made so that it is easy to change connection parameters later; (2) have connections be persistent (Apache::DBI); (3) have one point in each module at which the connection is made for that module; (4) in a given process, share all connections (i.e. connection is a singleton or is managed by a singleton); (5) Have modules that require database access manage their own connection rather than require that a database handle be passed to them; (6) Minimize change from current solution.

The problem with my current solution is that

in a persistent environment (mod_perl) the class data ($dbh) gets initizalized only once, and potentially, the database connection referenced by $dbh can go away due to timeout or some other problem because the process can "live" for a long time. Apache::DBI is capable of checking for this, by "pinging" the database but it doesn't really get a chance to do this, because the connection is getting made only at BEGIN time, when the module is "use"-d.

Example of flawed code is below. MyProject::Dbh "isa" Apache::Singleton::Process that makes a connection using the correct DSN, user, and password using DBI. Apache::DBI is used as well to make the connections persistent, but that is beside the point.

use MyProject::Dbh; my $dbh = MyProject::Dbh->instance->dbh; sub method1 { $dbh->do("... query goes here ..."); } sub method2 { my $sth = $dbh->prepare("... another query ..."); $sth->prepare; #... } } 1;
My question, then, what is a better way to manage the connection? Should it be in instance data rather than class data? Should it be set in each method that uses the database (ugly)? I am pleased almost all features of the current approach except for its flaw of never calling connect after initialization (which in Apache::DBI would take care of returning a good connection).

Replies are listed 'Best First'.
Re: Problem managing persistent database connections in modules
by LanceDeeply (Chaplain) on Jul 25, 2002 at 20:54 UTC
    mp-

    Here's one way to manage your connections. You can create a wrapper class around the actual connection. i've done some *basic* connection management for Win32::ODBC.

    (1) have a single place in the code where all connections are made so that it is easy to change connection parameters later;

    I kept a default connection string in the dbConnectionClass. All new connections that do not have a connection string specified use the default connection string.

    (2) have connections be persistent (Apache::DBI);
    The (Win32::ODBC) connections persist in connection pools hashed on their connectionString. a pool is an array of db connections.

    (3) have one point in each module at which the connection is made for that module;
    I propose that you call new dbConnection liberally and let the underlying connection pooling manage the number of connections kept open.

    (4) in a given process, share all connections (i.e. connection is a singleton or is managed by a singleton);
    yep...

    (5) Have modules that require database access manage their own connection rather than require that a database handle be passed to them;
    yes. each method that requires db access should just create a new dbConnection. (you dont care wether a new one is really created or one is pulled from a pool)
    package myFoo; use strict; use warnings; use dbConnection; sub new { my $self = bless( {}, shift ); $self->{id} = shift; my $db = new dbConnection(); # # build sql # load from $db # }

    # # this is not my production code... i had to chop it down significantl +y to for the purpose of this example # although i welcome comments/suggestions! # package dbConnection; use strict; use warnings; use Win32::ODBC; my %_ConnectionPools; my $_DefaultConnectionString; sub DefaultConnectionString { @_ ? $_DefaultConnectionString = shift : $_DefaultConnectionString; } sub _PoolConnection { my $poolname = shift; my $connection = shift; my $pool = _GetPool($poolname); push @$pool,$connection; } sub _GetPool { my $poolname = shift; my $pool = $_ConnectionPools{$poolname}; if (!defined $pool) { my @connections; $pool = \@connections; $_ConnectionPools{$poolname} = $pool; } return $pool; } sub new { my $self = bless( {}, shift ); $self->{_ConnectionString} = shift; # # check if any connection exist in pool # my $pool = _GetPool( $self->{_ConnectionString} ); my $connection = shift @$pool; if ( ! $connection ) { # # no connection exists, create new connection # $connection = new Win32::ODBC( $self->{_ConnectionString} ); if ( ! $connection ) { die "Could not connect to [" . $self->{_ConnectionString} +. "]"; } } $self->{_Connection} = $connection; return $self; } sub DESTROY { my $self = shift; _PoolConnection($self->{_ConnectionString}, $self->{_Connection} ) +; $self->{_Connection} = 0; } 1;


    Hope this was helpful!
      Your reply was helpful. I now have the following to create a singleton database handle.
      package MyProject::DbhSingleton; use Apache::Singleton::Request; use base (qw Apache::Singleton::Request); sub _new_instance { my $dbh = DBI->connect($dsn, $user, $pass, $attr) or die DBI->errstr +; }
      This would work if I called it within every method (sub) that does database access, but I'm looking for a way to avoid going to that extreme.
Re: Problem managing persistent database connections in modules
by mfriedman (Monk) on Jul 25, 2002 at 20:17 UTC
    I have set up a rather simple "singleton" type class to share a single database connection among several objects (about 20 in all) in a large application. The code I used follows the examples in Damian Conway's excellent book about OO Perl.

    pacakge MyProject::DBH; use DBI; my $DBH; # lexical scope outside the constructor # makes it available to all calls to new(). sub get_dbh { if ref($DBH) eq 'DBI::db') { # dbh already created, so return it return $DBH; } else { # connect to the DB and return the handle # (assume $user, $pass and $dsn come from somewhere) $DBH = DBI->connect($dsn, $user, $pass); return $DBH; } }

    Then, it's just a simple matter of every object calling MyProject::DBH->get_dbh; to get the same database handle.

      Could you give an example of where you call MyProject::DBH->get_dbh in a module and where you store the database handle? I.e., do you call it from the constructor then store the database handle in the object as instance data, or do you call it from each object method that needs a database handle?
        In that project, I had each class which needed access to the DB call MyProject::DBH->get_dbh in its constructor and store the returned database handle in the instance data. Then, it's available for each method that needs it in $self->{'dbh'}.

        You could just as easily make the DBH a package variable, but doing it this way seemed "neater" despite the increaed number of calls to get_dbh.

Re: Problem managing persistent database connections in modules
by Ryszard (Priest) on Jul 25, 2002 at 18:24 UTC
    Persistance is relativly easy to do, and it sounds as if you're most of the way there.

    In a non-persistant world I manage my database connections via a database handler. Basically I can call and "cache" any amount of statements and handles I wish.

    In a persistant world, as you rightly mention the database handles are kept open by mod_perl. From memory mod_perl will go and check the connection is still up, and if not it will bring it back up. So in effect mod_perl manages your connections for you. (I've read the theory, but not used it IRL yet, so I'll stand corrected here).