NAME
Activator::DB - Wrap DBI with convenience subroutines and consistant access accross all programs in a project.
Synopsis
use Activator::DB;
my $db = Activator::DB->connect('default'); # connect to default db
Get a single row:
my @row = $db->getrow( $sql, $bind, @args ); my $rowref = $db->getrow_arrayref( $sql, $bind, @args );
Get hashref of col->value pairs:
my $hashref = $db->getrow_hashref( $sql, $bind, @args );
Get all rows arrayref (these are identical):
my $rowsref = $db->getall( $sql, $bind, @args ); my $rowsref = $db->getall_arrayrefs( $sql, $bind, @args );
Get all rows ref: with each row a hashref of cols->value pairs:
my $rowsref = $db->getall_hashrefs( $sql, $bind, @args );
do
any query ( usually INSERT, DELETE, UPDATE ):my $id = $db->do( $sql, $bind, @args );
do
query, but return id instead of success.:my $id = $db->do_id( $sql, $bind, @args ); ( NOTE: this is very mysql dependant at the moment)
Get data from a different db for a while:
$db->connect('alt'); # connect to alternate db # do something $db->connect('def'); # reset to default connection # do something else
Transactions (NOT YET IMPLEMENTED)::
my $altdb = Activator::DB->connect('altdb'); $db->begin_work(); $db->do( @stuff ); $db->do( @more_stuff ); $db->commit();
DESCRIPTION
Activator::DB
module provides convenience and total consistency to accessing a database throughout a project. The idea is to reduce typing for the common cases, and remove worrying about connections. This module is a wrapper for DBI providing these advantages:
Provides connect string aliases centrally configured.
Provide consistent arguments handling to all query functions.
Connection caching without Apache::DBI (allows use of library/model code in crons AND website).
Connection and query debug dumps using your project or module level
Activator::Log
config, or on a per-query basis.Allows all code in your project/team/company to access the db in a consistent fashion.
By default, dies on all errors enforcing try/catch programming
Implemented as a singleton so each process is guranteed to be using no more than one connection to each database from the pool.
Disadvantages:
If you know DBI, you don't necessarily know
Activator::DB
NOT THREAD SAFE
Only tested with MySql
CONFIGURATION
This module uses Activator::Registry to automatically choose default databases, and Activator::Log to log warnings and errors.
Registry Setup (from Activator::Registry)
This module expects an environment variable ACT_REG_YAML_FILE to be set. If you are utilizing this module from apache, this directive must be in your httpd configuration:
SetEnv ACT_REG_YAML_FILE '/path/to/config.yml'
If you are using this module from a script, you need to insure that the environment is properly set using a BEGIN block:
BEGIN{
$ENV{ACT_REG_YAML_FILE} ||= '/path/to/config.yml'
}
Registry Configuration
Add an Activator::DB
section to your project YAML configuration file:
'Activator::Registry':
log4perl<.conf>: # Log4perl config file or definition
# See Logging Configuration below
'Activator::DB':
default: # default configuration for all connections
connection: <conn_alias>
## The rest of this section is optional
config:
debug: 0/1 # default: 0, affects all queries, all aliases
reconn_att: <int> # attempt reconnects this many times. default: 3
reconn_sleep: <int> # initial sleep seconds between reconnect attempts.
# doubles every attempt. default: 1
attr: # connection attributes. Only AutoCommit at this time
AutoCommit: 0/1 # default: 1
## You must define at least one connection alias
connections:
<conn_alias>:
user: <user>
pass: <password>
dsn: '<DSN>' # see perldoc DBI for descriptions of valid DSNs
# MySql Example: DBI:mysql:<DBNAME>:<DBHOST>
## These attributes and config are all optional, and use the default from above
attr:
AutoCommit: 0/1
config:
debug: 0/1 # only affects this connection
USAGE
This module can be used either pseudo-OO or static on multiple databases. I say pseudo-OO, because you don't call new: this module auto-vivicates a singleton object whenever you connect for the first time.
- ## pseudo-OO example:
-
my $db = Activator::DB->connect( 'db_alias' ); $db->query_method( $sql, $bind, @args ); $db->connect( 'alt_db_alias' ); $db->query_method( $sql, $bind, @args ); $db->connect( 'db_alias' ); $db->query_method( $sql, $bind, @args );
- ## Static formatted calls require that you dictate the connection for every request. So, the above can also be done as:
-
Activator::DB->query_method( $sql, $bind, connect => 'db_alias', @args ); Activator::DB->query_method( $sql, $bind, connect => 'alt_db_alias', @args ); Activator::DB->query_method( $sql, $bind, connect => 'db_alias', @args );
- ## However, the common use case for this module is:
-
my $db = Activator::DB->connect( 'db_alias' ); $db->query_method( $sql, $bind, @args ); ### do some perl $db->query_method( $sql, $bind, @args ); ### do some perl $db->query_method( $sql, $bind, @args ); ### do some perl ... etc.
connect() Usage
my $db = Activator::DB->connect('my_db'); # connect to my_db
my $db->connect('default'); # connect to default db
my $db->connect('def'); # shortcut to default db
my $db->connect(); # shortercut to default db
connect() Caveat
Note that connect()
always returns the singleton object, which in some usage patterns could cause some confusion:
my $db1->connect('db1'); # connect to db1
$db1->query( $sql, $bind, @args ); # acts on db1
my $db2->connect('db2'); # connect to db2
$db2->query( $sql, $bind, @args ); # acts on db2
$db1->query( $sql, $bind, @args ); # still acts on db2!
For this reason, it is highly recommended that you always use the same variable name (probably $db
) for the Activator::DB object.
Query Methods Usage
Every query function takes named arguments in the format of:
Activator::DB->$query_method( $sql, $bind, opt_arg => <opt_value> );
Mandatory Arguments:
sql : sql statement string
bind : bind values arrayref
Optional Arguments: conn => alias of the db connection (default is 'default') NOTE: this changes the connection alias for all future queries attr => hashref of attributes to use for ONLY THIS QUERY Supported: AutoCommit debug => pretty print sql debugging lines
# NOT YET SUPPORTED
slice => possible future support for DBI::getall_hashref
max_rows => possible future support for DBI::getall_hashref
Examples:
- ## Simple query:
-
my @row = $db->getrow( $sql );
- ## Needy query:
-
my $res = $db->do( $sql, $bind, connect => 'altdb', # changes the alias for future connections! attr => { AutoCommit => 0, }, debug => 1, );
Query Failures & Errors
All query methods die on failure, and must be wrapped in a try/catch block.
eval {
Activator::DB->query_method( $sql, $bind, @args );
};
if ($@) {
# catch the error
}
We highly recommend (and use extensively) Exception::Class::TryCatch which allows this syntactic sugar:
try eval {
Activator::DB->query_method( $sql, $bind, @args );
};
if ( catch my $e ) {
# rethrow, throw a new error, print something, AKA: handle it!
}
Errors Thrown:
connection failure - could not connect to database
sql missing - query sub called without 'sql=>' argument
connect missing - static call without 'connect=>' argument
prepare failure - failure to $dbh->prepare
execute failure - failure to $dbh->execute
alias_config missing - connection alias has no configuration
activator_db error - sub _warn_or_die() died without error args passed in
fetch failure - $sth->fetch* call failed
do failure - $dbh->do call failed
METHODS
getrow
getrow_arrayref
getrow_hashref
Prepare and Execute a SQL statement and get a the result of values back via DBI::fetchrow_array(), DBI::fetchrow_arrayref(), DBI::fetchrow_hashref() respectively. NOTE: Unlike DBI, these return empty array/arrayref/hashref (like DBI::fetchall_arrayref does, instead of undef) when there are no results.
Usage:
my @row = $db->getrow( $sql, $bind, @args )
my $rowref = $db->getrow_arrayref( $sql, $bind, @args )
my $hashref = $db->getrow_hashref( $sql, $bind, @args )
getall
getall_arrayrefs
getall_hashrefs
Prepare and Execute a SQL statement, and return a reference to the result obtained by DBI::fetchall_arrayref(). Returns an empty arrayref if no rows returned for the query.
getall()
is an alias forgetall_arrayrefs()
and they both return an arrayref of arrayrefs, one arrayref of values for each row of data from the query.$rowrefs is [ [ row1_col1_val, row1_col2_val ], [ row2_col1_val, row2_col2_val ], ];
getall_hashrefs()
returns an arrayref of of rows represented by hashrefs of column name => value mappings.$rowrefs is [ { col1 => val, col2 => val }, { col1 => val, col2 => val }, ];
my $rowref = $db->getall( $sql, $bind, @args )
my $rowref = $db->getall_arrayrefs( $sql, $bind, @args )
my $rowref = $db->getall_hashrefs( $sql, $bind, @args )
do
Execute a SQL statement and return the number of rows affected. Dies on failure.
Usage:
my $res = $db->do( $sql, $bind, @args )
do_id
Execute a SQL statement that generates an id and return the id. Dies on failure.
Usage:
my $id = $db->do_id( $sql, $bind, @args )
SEE ALSO
DBI, Activator::Registry, Activator::Log, Activator::Exception, Exception::Class::DBI, Class::StrongSingleton, Exception::Class::TryCatch
AUTHOR
Karim Nassar
COPYRIGHT
Copyright (c) 2007 Karim Nassar <karim.nassar@acm.org>
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.