Apache::DBI::Cache(3)
π Apache::DBI::Cache(3) π
okay bestie so this is the user-contributed Perl manual page for Apache::DBI::Cache, and trust, it's a whole vibe. let's get into it π¦
β¨ NAME β¨
Apache::DBI::Cache β it's a DBI connection cache, periodt π
β¨ SYNOPSIS β¨
use Apache::DBI::Cache debug=>3, bdb_env=>'/tmp/tmp',
plugin=>'Apache::DBI::Cache::mysql',
plugin=>['DBM', sub {...}, sub {...}],
...;
that's it, that's the whole entrance. iconic π
β¨ DESCRIPTION β¨
so this module is the alternative to the famous Apache::DBI module. just like Apache::DBI does, it gives you persistent DBI connections β the connections stay alive instead of getting yeeted every time.
and the range?? immaculate. it works with mod_perl1, mod_perl2, and honestly even standalone. versatile queen π
πΈ WHY ANOTHER MODULE FOR THE SAME? πΈ
ngl, Apache::DBI has a bunch of limitations. let's list them:
- first of all, you can't get multiple connections with the same parameters. a super common scenario is using one connection to do transactions and another one to do simple lookups in the same database. with
Apache::DBI, you're very likely to get the same connection when you actually meant to use different ones. tragic π - with
Apache::DBI, all connections are reset at the end of a request. every single one. no cap. Apache::DBIdoesn't regard database-specific functions to cache handles more aggressively. like, a mysql DSN can look like
dbi:mysql:test:localhost:3306
or it can look like
dbi:mysql:host=localhost;db=test
both of these point to the same database, but for Apache::DBI they're two completely different things π. Apache::DBI::Cache recognizes these two by means of a mysql plugin. slay.
- the plugin even recognizes connections to different databases on the same mysql server as the same connection, and it issues a
"USE database"command before returning the actual handle to the user. so withApache::DBI::Cachethe overall number of connections to a DB server can be dramatically reduced. the efficiency?? we love to see it π
π¦ HOW DOES IT WORK? π¦
to decide whether to use Apache::DBI::Cache or not, it's essential to know how it actually works. buckle up.
- same as
Apache::DBI,Apache::DBI::Cacheuses a hook provided by theDBImodule to interceptDBI->connect()calls. and yes,Apache::DBI::Cachealso maintains a cache of active handles. - when a new connection is requested and the cache is empty, a new connection is established and returned to the user. at this point it is not cached at all. this is where
Apache::DBI::Cachediffers fromApache::DBIβ plot twist β¨ - later, either
disconnectis called on the handle, or it simply goes out of scope and the garbage collector calls aDESTROYmethod if one is provided. both of these events are intercepted byApache::DBI::Cache. and only then is the handle put in the cache. - which means a handle is never really disconnected.
$dbh->{Active}will always return true no matter how many times you calldisconnect. also, you can prevent a handle from getting reused by simply not forgetting it. iykyk π
β¨ USAGE β¨
different from Apache::DBI, Apache::DBI::Cache must be used, not required. that means its import function must be called.
when you're using it with mod_perl (versions 1.x or 2.x), the best place to do this is in a startup.pl or in a <Perl> section in the httpd.conf. go check the mod_perl documentation for more info bestie π«Ά
after that, DBI->connect is called as usual. no special treatment needed. you just vibe.
when Apache::Status or Apache2::Status is used, Apache::DBI::Cache provides an extra menu item to show statistics on handles. and the loading order of Apache::Status and Apache::DBI::Cache?? irrelevant. doesn't matter, it just works π
π FUNCTIONS π
import β the "use" parameter
parameters to the "use" statement are given in a "key => value" fashion.
use Apache::DBI::Cache debug=>3, logger=>sub {...},
plugin=>['driver', sub {}, sub {}],
plugin=>'Apache::DBI::Cache::mysql',
use_bdb=>1,
bdb_env=>'/tmp/mybdbenv',
bdb_memcache=>20*1024,
...;
pluginβ loads a plugin, see also"PLUGINS"below. the plugin can be specified as a 3-element array or by name. in the second case,importsimplyuses the module. this option can be given multiple times.use_bdb,bdb_envandbdb_memcacheβApache::DBI::Cachecan use BerkeleyDB as a shared memory implementation to maintain statistics for a group of processes instead of a single process. (yes the original says "BerleleyDB", we're being cute about it, moving on π)"use_bdb"specifies whether to use BerkeleyDB or not. if omitted,Apache::DBI::Cachewill try to load and use BerkeleyDB. if that fails, it silently provides per-process statistics. if"use_bdb"is true,Apache::DBI::Cachedies if it cannot use BerkeleyDB. if"use_bdb"is false, per-process statistics are maintained and BerkeleyDB is not used."bdb_env"specifies a path to a directory where BerkeleyDB can put its temporary files. if omitted,/tmp/Apache::DBI::Cacheis used. the parent directory of this directory must exist and be writeable. no exceptions bestie."bdb_memcache"specifies the size of the shared memory segment that is allocated by BerkeleyDB. depending on the number of handles in your configuration, a few kilobytes are enough. if omitted, 20 kB are used."bdb_env"and"bdb_memcache"can also be specified by theAPACHE_DBI_CACHE_ENVPATHandAPACHE_DBI_CACHE_CACHESIZEenvironment variables. options options options β¨
debugβ set a debug level. under mod_perl this is almost irrelevant, see"logger"below.loggerβ here a logger function can be specified. it is called with the message verbosity level as the first parameter. the remaining parameters are concatenated to build the actual message.
currently there are 2 verbosity levels used, 1 and 2. 0 is reserved for real errors. 1 mentions that the module has been initialized. 2 rattles off normal processing messages.
Apache::DBI::Cache provides 2 logger functions. one is controlled by the "debug" level setting (see above). a message is printed to STDERR if its level is equal or greater than the current debug level.
the other logger is used when running under mod_perl. it is mainly controlled by the Apache "LogLevel" setting. messages at level 0 are printed as $log->error, level 1 as $log->info, and level 2 as $log->debug. for level 2 messages, additionally the current debug level is checked to be greater or equal to 2.
delimiterβ here the internal key delimiter can be changed. it defaults to"\1". changing it is necessary only when your DSN, username or password contain it, or to provide more readable debugging messages.
statistics
returns a reference to the statistics hash. if BerkeleyDB is used, it is tied to BerkeleyDB::Btree.
statistics_as_html
returns a reference to an array of HTML fragments. if mod_perl and Apache::Status or Apache::Status2 is used, the output of this function is shown under http://HOST/STATUS/URI?DBI_conn. cute right? πΈ
plugin( 'name', \&mangle, \&setup )
installs a new plugin, see "PLUGINS" below. if a plugin for the specified database type was already installed, it is returned as a 2-element list:
($old_mangle, $old_setup)=
plugin( 'name', \&new_mangle, \&new_setup );
if called with a name only, the current plugin is returned:
($old_mangle, $old_setup)=plugin( 'name' );
to delete a plugin, call:
($old_mangle, $old_setup)=plugin( 'name', undef, undef );
connect_on_init
call this function multiple times with parameters you would pass to "DBI->connect" before calling Apache::DBI::Cache::init, i.e. in your "startup.pl". then "init" will establish all these connections. pre-loading the vibes β¨
init
this function is called once per child process to initialize Apache::DBI::Cache. if mod_perl is used, this is done automatically in a PerlChildInitHandler.
finish
this function must be called before a process is going to terminate. under mod_perl it is automatically called in a PerlChildExitHandler.
as of version 0.08, calling this function is optional. so you can relax a lil.
undef_at_request_cleanup( \$dbh1, \$dbh2, ... )
when an application uses global variables to store handles, they probably won't be reused, because a global variable is... well... global. this can be fixed by explicitly undefining these handles at request cleanup, or by using this function. it simply collects all handle references passed in between 2 calls to Apache::DBI::Cache::request_cleanup. when Apache::DBI::Cache::request_cleanup is called, all these handles are undefined. the first call to this function during a request cycle installs Apache::DBI::Cache::request_cleanup as a PerlCleanupHandler.
with mod_perl2 this requires the PerlOption "GlobalRequest" to be set:
PerlOption +GlobalRequest
in your httpd.conf.
request_cleanup
this is the PerlCleanupHandler. if Apache::DBI::Cache is used standalone, the application can call it from time to time.
β¨ EXPORT β¨
nothing. nope. zero. it exports nothing π
β¨ DBI SUBCLASSING β¨
for a module like Apache::DBI::Cache, coping with DBI subclasses is complicated. there are 2 problems to solve.
first β make sure that our "disconnect" and "DESTROY" methods get called instead of the original ones. Apache::DBI::Cache solves this by inserting its own methods into the foreign class.
- hence, if a subclass provides
"disconnect"and"DESTROY"methods, they will never be called. this is ugly, but it works in most cases. we're being honest about it bestie π
second β to insert our methods into the subclass, we need to know its name. to create a subclassed DBI handle, you call either
DBI->connect( $dsn, $user, $passwd, {RootClass=>SUBCLASS} );
or
SUBCLASS->connect( $dsn, $user, $passwd, {} );
the first case is simple, since the attribute hash is passed to our connect method. unfortunately, the second case is not simple, since "SUBCLASS" is known only by DBI::connect. this is solved by searching the current call stack for the DBI::connect call. then we use its first parameter.
- that works for me, but it's even uglier. if you encounter problems, don't hesitate to mail me. fr fr π«Ά
β¨ Class::DBI and Ima::DBI β¨
to make "Class::DBI" or "Ima::DBI" work with "Apache::DBI::Cache", see Apache::DBI::Cache::ImaDBI. that's the plug π
β¨ PLUGINS β¨
okay bestie, so plugins are how you customize the caching for specific database types π They can do three iconic things: swap up the caching key, run database commands right before a handle gets handed back to you, or straight up block handle caching entirely for that database type. no cap.
There can only be one plugin per database type at a time. periodt. that's the rule.
A plugin signs itself up by calling Apache::DBI::Cache::plugin and passing 3 parameters π«Ά The first one is just the name of the database type. It matches the DBI driver name. So a MySQL plugin passes the string "mysql" because the matching DBI driver is called "DBD::mysql". Meanwhile a PostgreSQL plugin passes either "Pg" or "PgPP" depending on which driver is actually being used. iykyk πΈ
The 2nd and 3rd parameters are CODE references β¨ The first gets called just before a connection is chosen from the cache or newly established, and the second gets called after the connection is made, just before it's returned to the caller. The first function can mangle the connection parameters, the second performs additional setup steps. From here on I'm calling them mangle and setup π
So a plugin registers itself like this:
Apache::DBI::Cache::plugin('Name', \&mangle, \&setup);
Normally it's implemented as its own separate module following this template β see Apache::DBI::Cache::mysql for example π
package Apache::DBI::Cache::DRIVER;
use strict;
BEGIN {
die "Please load Apache::DBI::Cache before"
unless defined &Apache::DBI::Cache::plugin;
...
Apache::DBI::Cache::plugin
(
'DRIVER',
sub {},
sub {}
);
}
1;
π Calling Conventions π
- mangle
($dsn, $user, $passwd, $attr, $ctx, $nocache)=
mangle($dsn, $user, $passwd, $attr);
mangle gets called with basically the same parameters as the original call to DBI->connect π The dbi:DRIVER: prefix is stripped from the DSN. It's expected to return similar values, plus an arbitrary context that later gets passed to setup, and an optional nocache flag.
If$nocacheis true, or if mangle returns an empty list, a brand new connection is made and the handle goes straight to the caller with no further processing. Also setup will not be called. A handle like that will not be cached ondisconnectorDESTROYπ«
mangle can change all the parameters. The MySQL plugin, for example, deletes the actual database name from the DSN, reformats it into a standard format, and adds the standard port if it was omitted. The database gets put in the context. slay π
- setup
$rc=setup($dbh, $dsn, $user, $passwd, $attr, $ctx);
The setup function performs extra setup steps on $dbh β¨ The MySQL plugin, for example, issues a USE database command using the database from the context.
A connection is considered dead if setup returns false π
π TODO π
- periodically ping all cached handles
- correct statistics when a process is finishes without calling
finish() - redirect BerkeleyDB errors to logger
π SEE ALSO π
Apache::DBI::Cache::mysqlApache::DBI
π AUTHOR π
Torsten Foertsch, <torsten.foertsch@gmx.net>
With suggestions from
Andreas Nolte < andreas dot nolte at bertelsmann dot de >
Dietmar Hanisch < dietmar dot hanisch at bertelsmann dot de > and
Ewald Hinrichs < ewald dot hinrichs at bertelsmann dot de >
π SPONSORING π
Sincere thanks to Arvato Direct Services (http://www.arvato.com/) for sponsoring this module and providing a test platform with several thousand DBI connections. iconic behavior honestly π«Ά
β COPYRIGHT AND LICENSE β
Copyright (C) 2005-2006 by Torsten Foertsch
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
and that's a wrap bestie π¦ this page is from perl v5.42.0, dated 2025-07-25, and it's the Apache::DBI::Cache(3) manpage. go cache those handles responsibly, mwah π
π¦ where this page comes from
- fedora 43: perl-Apache-DBI-Cache 0.08-52.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms