[Dbix-class] ROLLBACK seems to be skipped on 0.08

Brandon Black blblack at gmail.com
Fri Nov 2 02:38:25 GMT 2007


On 11/1/07, Louis Erickson <lerickson at rdwarf.net> wrote:
>
> Sorry to wake up a slightly old thread, but I've just been bit by this in
> an 0.07 to 0.08 upgrade, and found this thread.  (This bit me as soon as I
> started using 0.08.  I just started using it or I'd have asked earlier.)
>
> One difference between what I'm reading here and what I'm seeing in my own
> app is that I always do a txn_begin/txn_commit, and it does not work as
> I'd expect, either.
>

I suspect not, it's broken.

> (It starts at a transaction level of 1, which is incremented by the begin,
> and decremented by the commit, so that it never actually commits to the
> DB.  To either comment out the begin or add an extra commit works around
> it, despite being extremely goofy looking.)
>
> I do have a question regarding txn_do, though, for I don't understand how
> it can work properly with AutoCommit => 1.
>
> On Sun, 21 Oct 2007, Jesper Krogh wrote:
>
> > Ok.. maybe I didnt make it clear. The problem is that we "serialize"
> > object into several records (over 20 mostly) and this serialization
> > process should be done atomically, so I don't get any "half-objects" in
> > the database. It wasn't the individual record I was talking about.
> >
> > This dataset is conceptually "inconsistent" to the application if this
> > happens. But the database is of course not aware of this.
>
> This is the primary reason I was using manual txn_begin/txn_commit calls,
> and AutoCommit=>0.
>
> > txn_begin/commit and txn_do solves this.
>
> How does txn_do solve this?  This is the part I don't understand.  Perhaps
> one of the experts here can explain it.
>

The fact that 0.08 breaks backwards compatibility with 0.07 for people
who are using "AutoCommit => 0", and the fact that both versions are
effectively buggy for said users in the sense that they can't possibly
correctly support all usages, are DBIC deficiencies.  I should have
realized the mistake in the 0.08 changes, but they were spread out
over a very long time window, and apparently nobody who cares about
"AutoCommit => 0" bothered testing them.  These issues are basically
going to be resolved by slowly dropping support for "AutoCommit => 0"
altogether, as there's no sensible way to do it.  It's on my list,
hopefully this weekend I can get to this.

All of that aside, anyone who talks about "AutoCommit => 0" being a
required for properly supporting multi-statement transactions with
whatever appropriate level of transaction isolation is supported by
the underlying DBMS is on the wrong track.

You can have the same multi-statement transactions with the same
guarantees of serialization with or without AutoCommit at the DBI
level.  At the DBI levels and below, all the way to your database,
there is no difference between:

$dbh->{AutoCommit} = 0;
$dbh->do("INSERT ...");
$dbh->do("DELETE ...");
$dbh->commit;

and:

$dbh->{AutoCommit} = 1;
$dbh->begin_work;
$dbh->do("INSERT ...");
$dbh->do("DELETE ...");
$dbh->commit;

However, for the abstractions DBIC is trying to support, AutoCommit=>1
is really the only way to go.  AutoCommit=>0 would either require us
to require all sql-generating code be in explicitly marked txns
(marked by a begin_work-like call), which would suck for lots of
existing modules out there, or if we didn't do so, would require us to
somehow magically deal with ambiguously nested transaction contexts.
AutoCommit=>1 doesn't suffer from these issues.

As far as the DBIC-level txn api goes, "txn_do($coderef, at args)"
basically does something like the following pseudocode from the user
perspective:

sub txn_do {
  my ($self, $coderef, @args) = @_;
  eval {
    $dbh->begin_work;
    $coderef->(@args);
    $dbh->commit;
  };
  if(my $err = $@) {
    eval { $dbh->rollback };
    throw_exception($err);
  }
}

Except that there's a lot of other magic involved to handle
disconnects and transaction nesting and proper return values, etc.  We
can (and currently do) also support explicit txn_begin, txn_end, and
txn_rollback methods so that you can make your own little constructs
like the above.  However, nobody's come up with any sane example of
anything they'd want to do with those calls that can't be accomplished
via txn_do(), which saves you working out all the gory details
yourself and probably handles things better.

-- Brandon



More information about the DBIx-Class mailing list