[CDBI] Re: Apps using Class::DBI

Perrin Harkins perrin at elem.com
Thu Mar 30 00:15:59 BST 2006

On Wed, 2006-03-29 at 14:28 -0800, Bill Moseley wrote:
> Which part is unnecessary?

All of the "do_transaction" code ref stuff.  I've had some bitter
experiences with code refs and avoid them whenever possible.  I just use
a bare block to make the local() call work.

> > These days I have started keeping AutoCommit on and turning it off for
> > blocks where I want a transaction with local $dbh->{AutoCommit}, but
> > that's all DBI-level stuff.  Class::DBI doesn't interfere with it.
> Do you need to even change AutoCommit?  I just call $dbh->begin_work.
> (Although John Siracusa currently is working out a problem with
> rollback's failing with DBD:Pg and this method, IIRC).

I haven't tried that, but what I like about local $dbh->{AutoCommit} is
that it gets reset for me when I leave the block.

> One thing DBIC does is handle nested transactions.

Are you talking about real (database level) nested transactions, or just
avoiding calling commit inside of a sub that's been called from inside a
transaction?  I haven't needed either, so far, but my local() approach
provides a similar benefit, i.e. AutoCommit goes back to what it was
when you entered the block, and if it was already off it stays off and
no commit is sent.  There would be an issue if I wanted to call commit
explicitly though, instead of letting it be called automatically when I
pop out of the block.

> The do_begin, do_rollback,
> and do_commit methods just checks a nested level to handle the nested
> transactions.

And they just decide whether or not to really call commit?  That would
be useful, if you prefer begin_work/commit to the AutoCommit approach.
I don't see these methods in DBIx::Class though.  Maybe they changed
names since you wrote this code?

> You still see stuff that's not necessary?
> sub do_transaction {
>     my( $class, $code, @args ) = @_;
>     $class->_invalid_object_method('do_transaction()') if ref $class;
>     my @return_values = ();
>     $class->do_begin;
>     my $wa = wantarray;  # because wantarray is undefined inside the eval.
>     eval {
>         @return_values = $wa ? $code->(@args) : scalar $code->(@args);
>         $class->do_commit;
>     };
>     return wantarray ? @return_values : $return_values[0]
>         unless $@;
>     my $error = $@;  # save due to eval for rollback
>     # CDBI to reload the object
>     $class->clear_object_index;
>     eval{ $class->do_rollback; };
>     $class->_croak("Transaction aborted: $error; Rollback failed: $@")
>         if $@;
>     $class->_croak("Transaction aborted (rollback successful): $error");
> }

Most of this code is just trying to deal with problems caused by using
code refs instead of a bare block.  I don't use the object index, so I
don't need that part either.  What you're left with is pretty much pure
DBI, except for the help with calling commit in nested transactions.
I'd like to see that as a separate DBIx:: module, since it doesn't need
to interact with ORM to work.  Maybe someone has already done it.

- Perrin

More information about the ClassDBI mailing list