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

i have written a my first db app in perl, using multiple scripts.
I wish to know if there is a way in which i may write the connect code once and call it each time a connection is needed.

The connect code looks like this
my $dbh = DBI->connect("DBI:Sybase:CRAP", "sa", "");


i have tried using require and do but with no luck.
Any assistance would be greatly appreciated.

In search of enlightenment jasmine

Replies are listed 'Best First'.
Re: multiple db connects
by btrott (Parson) on Dec 21, 2000 at 12:10 UTC
    You can do this in many ways. One obvious way is to just wrap this in a function:
    sub database_handle { my $dbh = DBI->connect("DBI:Sybase:CRAP", "sa", ""); die "connect failed: $DBI::errstr" unless $dbh; $dbh; }
    Then get a new database handle using
    my $dbh = database_handle();
    Is this what you wanted? Or did you want to save the handle somehow, and return the already-open connection if it's open already? You could do that like this:
    { my $dbh; sub database_handle { return $dbh if defined $dbh; $dbh = DBI->connect("DBI:Sybase:CRAP", "sa", ""); die "connect failed: $DBI::errstr" unless $dbh; $dbh; } }
    And you'd get access to the handle the same way, by calling database_handle. This will return an already-open connection.

    Or you could get trickier and wrap this in an object wrapper around DBI. This is something I like to do, because I like to write code that works on different databases, so I provide one main class that wraps around DBI, then subclass that to provide database-specific functionality (stuff that differs between DBD drivers, etc.).

    Here's a simple class:

    package My::DB; use strict; sub new { my $class = shift; $dbh = DBI->connect("DBI:Sybase:CRAP", "sa", ""); die "connect failed: $DBI::errstr" unless $dbh; bless { handle => $dbh }, $class; } sub handle { $_[0]->{handle} }
    You could use this like this:
    my $dbh = My::DB->new->handle;
    This may seem relatively useless (why I am returning an object containing only an open database handle? why not just return the handle itself?), but the way I use this is, I don't actually use any of the DBI methods directly in my main code. I have wrappers around DBI methods that do a bit more, like do some automatic exception handling, bind variable processing, etc.

    For example, I have an execute method that does this:

    sub _execute { my $self = shift; my($sql, $place, $finish) = @_; my($sth, $rv); eval { $sth = $self->prepare($sql); $rv = $sth->execute(ref $place eq "ARRAY" ? @$place : ()); $sth->finish if $finish; }; if ($@) { My::Exception::DB->throw(sql => $sql, error => $@); } return $finish ? $rv : $sth; }
    And my prepare method uses prepare_cached, instead of just plain prepare. And so on.
      My first thought is that unless you are connecting to more than one DB, you don't need a routine. You leave the connection open until you are done. So any routine should handle some sort of argument for which DB to connect to.

      I have a question of style/usage regarding the die clause in the subs... Would we still want to call such a function thusly:
      my $dbh->db_handle($db_name) || die "SNAFU getting to $db_name: $!"; or my $dbh->db_handle($db_name) || &explain_to_user_that_db_unavailable( +$db_name );
      Or something like that? Especially if this is a CGI wouldn't we want to use a function to tell the user to quit hitting refresh until the server is fixed? The die clause still returns a false value for the sub call, right? But this could cause errors if not handled in the main clause, right?
        Sure, you could do whatever you wanted, really. Personally I like to die when something seems like an obviously fatal error. That doesn't mean that your *program* will die, because you can catch the die in an eval block. Which is what I do.

        You also said:

        > The die clause still returns > a false value for the sub call, right?
        Well, no; the die just *dies*. Your sub won't return at all. Your program will die, unless you have an eval block, in which case the die will shoot you out to the closest eval block, and will populate $@ with the error message. And then you said:
        > But this could cause > errors if not handled in the main clause, right?
        Certainly. That's why the errors should be handled. :)

        Instead of dying, then, you could have your sub return a false value. That would work. Then you could do your checking out in the caller. Some people find that preferable, I'm sure, and that's fine; my preference is to throw exceptions as soon as something bad happens. Then I catch them.

Re: multiple db connects
by snowcrash (Friar) on Dec 21, 2000 at 12:23 UTC
    not quite sure if i understand your question correctly, but i'd suggest doing something like that:
    1) write a simple module the handles the database access:
    package JasminesDB; use strict; use DBI; sub db_connect(){ $dbh = DBI->connect("DBI:Sybase:CRAP", "sa", "") || die ("Can't connect to database: $DBI::errstr"); return $dbh; } 1;
    2) then, inside your script:
    use JasminesDB; my $dbh = JasminesDB::db_connect();
    yt, snowcrash

      A useful addition to this might be to stash the returned db handle.

      If you're running Apache then then you can do something like the following to share a single connection amongst several scripts:

      if (! $Global::var{'dbh'}) { my $sdn = "DBI:mysql:database=$db;host=$host"; my $dbh = DBI->connect($sdn, $user, $pass) || die ("Unable to con +nect to DB: $DBI::errstr"); $Global::var{'dbh'} = $dbh; } return ($Global::var{'dbh'});
        You can't "share a single connection among multiple scripts" if they all live in separate spaces, whether you're using Apache or not!

        If you were talking about mod_perl's Apache::Registry "scripts" (really, handlers coded on the fly from script-like things), then you don't need to do any of this mess either. Just include Apache::DBI, and it autoshares for you!

        -- Randal L. Schwartz, Perl hacker

Re: multiple db connects
by PsychoSpunk (Hermit) on Dec 21, 2000 at 13:05 UTC
    While in scope and until you issue $dbh->disconnect you will have a database connection. So, as others have pointed out, you have to initiate the code via a sub in your required file. Recall that require does nothing more than act like include. No actual code in the required file will be executed without express written permission from the programmer.

    ALL HAIL BRAK!!!

      Actually the first time you require a file you execute the whole thing. The second time nothing happens.

      This is normally used with files that don't carry out any obvious actions. But it is very important to know that actions are taken if your require needs to carry on specific initializations...