nmerriweather has asked for the wisdom of the Perl Monks concerning the following question:

I've begun porting my db interaction code to a transaction based approach.

I have 2 db handles 'DBH' and 'DBH_Write' , each with their own name/pass

DBH is used exclusively for selects , DBH_Write is used for transactional locking for record creation

I've started getting a "Already in a transaction" error on my first use of the DBHwriter though, and i can't figure out how or why

i've set this:
$this->{'DBH_Write'}->{TraceLevel} = 14 ;
and i get this:
begin_work in DBD::_::db for DBD::mysql::db (Apache::DBI::db=HASH(0x1c +96d90)~0x1c99d48) thr#18d6200 >> FETCH DISPATCH (DBI::db=HASH(0x1c99d48) rc1/2 @2 g0 ima40 +4 pid#4399) at /Library/Perl/5.8.6/darwin-thread-multi-2level/DBI.pm +line 1630 via /webserver/sites/test.com/lib/Object/User.pm line 301 1 -> FETCH for DBD::mysql::db (DBI::db=HASH(0x1c99d48)~INNER 'AutoCo +mmit') thr#18d6200 1 <- FETCH= '' at /Library/Perl/5.8.6/darwin-thread-multi-2level/DBI +.pm line 1630 via /webserver/sites/test.com/lib/Object/User.pm line 3 +01 >> set_err DISPATCH (DBI::db=HASH(0x1c99d48) rc1/2 @3 g0 ima11 + pid#4399) at /Library/Perl/5.8.6/darwin-thread-multi-2level/DBI.pm l +ine 1630 via /webserver/sites/test.com/lib/Object/User.pm line 301 1 -> set_err in DBD::_::common for DBD::mysql::db (DBI::db=HASH(0x1c +99d48)~INNER 1 'Already in a transaction') thr#18d6200 !! ERROR: 1 'Already in a transaction' (err#1) 1 <- set_err= undef at /Library/Perl/5.8.6/darwin-thread-multi-2leve +l/DBI.pm line 1630 via /webserver/sites/test.com/lib/Object/User.pm l +ine 301 !! ERROR: 1 'Already in a transaction' (err#1) <- begin_work= undef at /webserver/sites/test.com/lib/Object/User. +pm line 301 via /webserver/sites/test.com/lib/Object/User.pm line 363 DBD::mysql::db begin_work failed: Already in a transaction at /webserv +er/sites/test.com/lib/Object/User.pm line 301.
the offending line in 301:
$_[0]->{'DBH_Write'}->begin_work
I've been tracing the mysql connection log, every call to the DB, this is the first time my code uses the DBH_Write handle. I've tried placing rollback and commit before that line, neither work.

can anyone offer insight?

Replies are listed 'Best First'.
Re: odd transaction behavior: dbi mysql
by pg (Canon) on Oct 21, 2005 at 02:05 UTC

    If AutoCommit is on, begin_work() will turn it off, until the transaction gets commited or rolled back, so this code works:

    use DBI; use strict; use warnings; my $dsn = "DBI:mysql:database=test;host=blah"; my $dbh = DBI->connect($dsn, 'root', 'abcd', {RaiseError => 1, AutoCom +mit => 1}); my $command = "update test set a = a + 1"; my $sth = $dbh->prepare($command); $dbh->begin_work(); $sth->execute(); $sth->execute(); $sth->execute(); $sth->execute(); $dbh->commit();

    If AutoCommit is off, then you are sort of in an implicit transaction already, and when you call begin_work is issues an error. I personally don't like this behavior, but this is how it works. If you run this code (the only difference is that AutoCommit is off:

    use DBI; use strict; use warnings; my $dsn = "DBI:mysql:database=test;host=blah"; my $dbh = DBI->connect($dsn, 'root', 'abcd', {RaiseError => 1, AutoCom +mit => 0}); my $command = "update test set a = a + 1"; my $sth = $dbh->prepare($command); $dbh->begin_work(); $sth->execute(); $sth->execute(); $sth->execute(); $sth->execute(); $dbh->commit();

    You get this error:

    DBD::mysql::db begin_work failed: Already in a transaction at math1.pl + line 10. DBD::mysql::db begin_work failed: Already in a transaction at math1.pl + line 10.

    Summary: the logic behind is, regardless whether I like it: If AutoCommit is on, and you want a transaction, obviously I have to turn it off for you as long as you remain in the transaction, so that you can decide the poitn to commit or rollback; But if AutoCommit is off, you are already in sort of transaction, why you start a transaction in a transaction?

Re: odd transaction behavior: dbi mysql
by jdporter (Paladin) on Oct 21, 2005 at 01:00 UTC
    Threading? AutoCommit?
      That was it - AutoCommit.

      I'm new to this, so hopefully someone can enlighten me:
      I set AutoCommit to 0 - it turns out that AutoCommit must be 1 in order to handle begin_work

      Is there any way to enforce all code happen within a begin / ( commit/rollback) bookends? It seems that with AutoCommit 0, there is no way to begin; and with autocommit 1 there is no way to force code to happen without an explicit transaction declaration.
Re: odd transaction behavior: dbi mysql
by perrin (Chancellor) on Oct 21, 2005 at 02:46 UTC
    Doesn't turning off AutoCommit implicitly begin a transaction? It may depend on what isolation level you set, but I thought this was the case. I think you only need to explicitly commit, not begin.