Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

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::TransHandlershould be used as the PerlTransHandler, and Book::ContentHandlershould 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


Copyright © 2003 O'Reilly & Associates. All rights reserved.


 
 
  Published courtesy of O'Reilly Design by Interspire