1 package DBIx::Class::Storage::TxnScopeGuard;
6 use Scalar::Util qw/weaken blessed refaddr/;
12 my ($class, $storage) = @_;
19 # we are starting with an already set $@ - in order for things to work we need to
20 # be able to recognize it upon destruction - store its weakref
21 # recording it before doing the txn_begin stuff
22 if (defined $@ and $@ ne '') {
23 $guard->{existing_exception_ref} = (ref $@ ne '') ? $@ : \$@;
24 weaken $guard->{existing_exception_ref};
29 $guard->{dbh} = $storage->_dbh;
32 bless $guard, ref $class || $class;
40 $self->{storage}->throw_exception("Refusing to execute multiple commits on scope guard $self")
41 if $self->{inactivated};
43 $self->{storage}->txn_commit;
44 $self->{inactivated} = 1;
50 return if $self->{inactivated};
52 # if our dbh is not ours anymore, the $dbh weakref will go undef
53 $self->{storage}->_verify_pid unless DBIx::Class::_ENV_::BROKEN_FORK;
54 return unless $self->{dbh};
56 my $exception = $@ if (
62 ! defined $self->{existing_exception_ref}
64 refaddr( ref $@ eq '' ? \$@ : $@ ) != refaddr($self->{existing_exception_ref})
71 carp 'A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back.'
72 unless defined $exception;
74 my $rollback_exception;
75 # do minimal connectivity check due to weird shit like
76 # https://rt.cpan.org/Public/Bug/Display.html?id=62370
77 try { $self->{storage}->_seems_connected && $self->{storage}->txn_rollback }
78 catch { $rollback_exception = shift };
80 if ( $rollback_exception and (
81 ! defined blessed $rollback_exception
83 ! $rollback_exception->isa('DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION')
85 # append our text - THIS IS A TEMPORARY FIXUP!
86 # a real stackable exception object is in the works
87 if (ref $exception eq 'DBIx::Class::Exception') {
88 $exception->{msg} = "Transaction aborted: $exception->{msg} "
89 ."Rollback failed: ${rollback_exception}";
92 $exception = "Transaction aborted: ${exception} "
93 ."Rollback failed: ${rollback_exception}";
97 "********************* ROLLBACK FAILED!!! ********************",
98 "\nA rollback operation failed after the guard went out of scope.",
99 'This is potentially a disastrous situation, check your data for',
100 "consistency: $rollback_exception"
115 DBIx::Class::Storage::TxnScopeGuard - Scope-based transaction handling
120 my ($self, $schema) = @_;
122 my $guard = $schema->txn_scope_guard;
124 # Multiple database operations here
131 An object that behaves much like L<Scope::Guard>, but hardcoded to do the
132 right thing with transactions in DBIx::Class.
138 Creating an instance of this class will start a new transaction (by
139 implicitly calling L<DBIx::Class::Storage/txn_begin>. Expects a
140 L<DBIx::Class::Storage> object as its only argument.
144 Commit the transaction, and stop guarding the scope. If this method is not
145 called and this object goes out of scope (e.g. an exception is thrown) then
146 the transaction is rolled back, via L<DBIx::Class::Storage/txn_rollback>
152 L<DBIx::Class::Schema/txn_scope_guard>.
158 Inspired by L<Scope::Guard> by chocolateboy.
160 This module is free software. It may be used, redistributed and/or modified
161 under the same terms as Perl itself.