A brief example using Class::DBI's example Music/CD database may help to explain:
for my $cd ( 1 .. 2 ) {
Music::CD->create(
{ cdid => $cd,
title => "Title of CD $cd",
year => '2006',
artist => 5,
}
);
for my $track ( 1 .. 5 ) {
Music::Track->create(
{ trackid => $cd . $track,
cd => $cd,
position => $track,
title => "Title of track $track",
}
);
}
}
Music::DBI->dbi_commit();
The above results in 13 calls to Ima::DBI's _mk_db_closure, which returns a database handle:
sub _mk_db_closure {
my ($class, @connection) = @_;
my $dbh;
return sub {
unless ($dbh && $dbh->FETCH('Active') && $dbh->ping) {
$dbh = DBI->connect_cached(@connection);
}
return $dbh;
};
}
_mk_db_closure and DBI->connect_cached will return the same database handle if the dbh->ping is successful. But if it's not, a new database handle is returned.If say, on the 8th call to _mk_db_closure, the ping fails, and a new database handle is returned. Wouldn't all uncommited transactions on the dead database handle be silently lost?
I realize that the possibility of the handle going dead, and a new one returned is remote. In practice, if the a handle goes dead, usually the database is down and a new handle won't be able to be created. However, the possibility exists.
So, is it possible that Class::DBI's mulitple potential calls to connect_cached during a single execution could result in lost transactions?
Thank you
Thank you for your response.
You say that it's unlikely. I'm attempting to determine the likelihood of this occuring. In other words, is it worth the effort to correct the problem.
The first scenario that comes to mind is a momentary network outage from the web server to the database server. Using my example from the original question:
1. Immediately before the 8th call to _mk_db_closure, there is a momentary network outage to the database server.
2. $dbh->ping is called (which on DBD::Oracle, does a 'select sysdate from dual')
I 'think' this is an immediate, no timeout operation.
ping would return false.
3. A new connection would attempted to be made.
With DBI->connect (on Oracle), I'm pretty sure
that it tries a few times to connect before
timing out and erroring. Before the timeout,
the network comes back up. A new dbh is created
and transactions are lost.
Another scenario is that our primarly database server fails over to the secondary node. Depending on how quickly the fail over happened, this could be a similar situation as the momentary network outage.
With your experience, would you agree that the above scenarios could result in the lost transaction problem?
Thank you, Perrin.
It's definitely safer to not try to reconnect during a web request. If you'd rather not touch Ima::DBI, you can override db_Main in your Class::DBI base class.
Thank you for your ensight.
Please allow me ask another question.
From reading your posts on various forums, it appears that your environment is similar to the environment I work in.
Are you concerned about this possibilty of lost transactions?
Do you override Ima::DBI's _mk_dbi_closure, or Class::DBI's db_Main in the transaction based applications you develop and support to ensure that connect is called just once per request, for mod_perl and/or plain mod_cgi?
Thank you, Perrin.
perlmonks.org content © perlmonks.org and Anonymous Monk, perrin
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03