JavaScript EditorFree JavaScript Editor     Free JavaScript Scripts 



Main Page Previous Section Next Section

A.12 Singleton Database Handles

Let's say we have an object we want to be able to access anywhere in the code, without making it a global variable or passing it as an argument to functions. The singleton design pattern helps here. Rather than implementing this pattern from scratch, we will use Class::Singleton.

For example, if we have a class Book::DBIHandle that returns an instance of the opened database connection handle, we can use it in the TransHandler phase's handler (see Example A-6).

Example A-6. Book/TransHandler.pm
package Book::TransHandler;

use Book::DBIHandle;
use Apache::Constants qw(:common);

sub handler {
    my $r = shift;
    my $dbh = Book::DBIHandle->instance->dbh;
    $dbh->do("show tables");
    # ...
    return OK;
}
1;

We can then use the same database handle in the content-generation phase (see Example A-7).

Example A-7. Book/ContentHandler.pm
package Book::ContentHandler;

use Book::DBIHandle;
use Apache::Constants qw(:common);

sub handler {
    my $r = shift;
    my $dbh = Book::DBIHandle->instance->dbh;
    $dbh->do("select from foo...");
    # ...
    return OK;
}
1;

In httpd.conf, use the following setup for the TransHandler and content-generation phases:

PerlTransHandler +Book::TransHandler
<Location /dbihandle>
    SetHandler perl-script
    PerlHandler +Book::ContentHandler
</Location>

This specifies that Book::TransHandler should be used as the PerlTransHandler, and Book::ContentHandler should be used as a content-generation handler. We use the + prefix to preload both modules at server startup, in order to improve memory sharing between the processes (as explained in Chapter 10).

Book::DBIHandle, shown in Example A-8, is a simple subclass of Class::Singleton that is used by both handlers.

Example A-8. Book/DBIHandle.pm
package Book::DBIHandle;

use strict;
use warnings;

use DBI;

use Class::Singleton;
@Book::DBIHandle::ISA = qw(Class::Singleton);

sub _new_instance {
    my($class, $args) = @_;

    my $self = DBI->connect($args->{dsn},    $args->{user},
                            $args->{passwd}, $args->{options})
        or die "Cannot connect to database: $DBI::errstr";

    return bless $self, $class;
}

sub dbh {
   my $self = shift;
   return $$self;
}
1;

Book::DBIHandle inherits the instance( ) method from Class::Singleton and overrides its _new_instance( ) method. _new_instance( ) accepts the connect( ) arguments and opens the connection using these arguments. The _new_instance( ) method will be called only the first time the instance( ) method is called.

We have used a reference to a scalar ($dbh) for the Book::DBIHandle objects. Therefore, we need to dereference the objects when we want to access the database handle in the code. The dbh( ) method does this for us.

Since each child process must have a unique database connection, we initialize the database handle during the PerlChildInit phase, similar to DBI::connect_on_init( ). See Example A-9.

Example A-9. Book/ChildInitHandler.pm
package Book::ChildInitHandler;

use strict;
use Book::DBIHandle;
use Apache;

sub handler {
    my $s = Apache->server;

    my $dbh = Book::DBIHandle->instance(
        { dsn     => $s->dir_config('DATABASE_DSN'),
          user    => $s->dir_config('DATABASE_USER'),
          passwd  => $s->dir_config('DATABASE_PASSWD'),
          options => {
              AutoCommit => 0,
              RaiseError => 1,
              PrintError => 0,
              ChopBlanks => 1,
          },
        }
    );

    $s->log_error("$$: Book::DBIHandle object allocated, handle=$dbh");
}
1;

Here, the instance( ) method is called for the first time, so its arguments are passed to the new _new_instance( ) method. _new_instance( ) initializes the database connection.

httpd.conf needs to be adjusted to enable the new ChildInitHandler:

PerlSetVar DATABASE_DSN    "DBI:mysql:test::localhost"
PerlSetVar DATABASE_USER   "foo"
PerlSetVar DATABASE_PASSWD "bar"

PerlChildInitHandler +Book::ChildInitHandler
    Main Page Previous Section Next Section
    


    JavaScript EditorJavaScript Validator     Web Manuals and Tutorials


    ©