use Sub::ScopeFinalizer qw( scope_finalizer ); { my $in_trans = eval { $dbh->begin_work() }; my $pending_rollback = scope_finalizer { local $@; eval { $dbh->rollback() } if $in_trans; }; code_that_touches_db(); $pending_rollback->disable(); $dbh->commit() if $in_trans; }