Massive cleanup of transaction handlers
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / TxnScopeGuard.pm
CommitLineData
6936e902 1package DBIx::Class::Storage::TxnScopeGuard;
1bc193ac 2
3use strict;
4use warnings;
c6e27318 5use Carp::Clan qw/^DBIx::Class/;
ed7ab0f4 6use Try::Tiny;
7d216b10 7use Scalar::Util qw/weaken/;
fd323bf1 8use namespace::clean;
1bc193ac 9
10sub new {
11 my ($class, $storage) = @_;
12
13 $storage->txn_begin;
7d216b10 14 my $guard = bless [ 0, $storage, $storage->_dbh ], ref $class || $class;
15 weaken ($guard->[2]);
16 $guard;
1bc193ac 17}
18
19sub commit {
20 my $self = shift;
21
22 $self->[1]->txn_commit;
23 $self->[0] = 1;
24}
25
26sub DESTROY {
27 my ($dismiss, $storage) = @{$_[0]};
28
3b7f3eac 29 return if $dismiss;
30
7d216b10 31 # if our dbh is not ours anymore, the weakref will go undef
32 $storage->_preserve_foreign_dbh;
33 return unless $_[0]->[2];
34
3b7f3eac 35 my $exception = $@;
c6e27318 36
a778f387 37 {
38 local $@;
36099e8c 39
40 carp 'A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back.'
41 unless $exception;
42
ed7ab0f4 43 my $rollback_exception;
7d216b10 44 # do minimal connectivity check due to weird shit like
45 # https://rt.cpan.org/Public/Bug/Display.html?id=62370
46 try { $storage->_seems_connected && $storage->txn_rollback }
ed7ab0f4 47 catch { $rollback_exception = shift };
c6e27318 48
ed7ab0f4 49 if (defined $rollback_exception && $rollback_exception !~ /DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION/) {
36099e8c 50 if ($exception) {
51 $exception = "Transaction aborted: ${exception} "
c6e27318 52 ."Rollback failed: ${rollback_exception}";
36099e8c 53 }
54 else {
55 carp (join ' ',
56 "********************* ROLLBACK FAILED!!! ********************",
57 "\nA rollback operation failed after the guard went out of scope.",
58 'This is potentially a disastrous situation, check your data for',
59 "consistency: $rollback_exception"
60 );
61 }
c6e27318 62 }
3b7f3eac 63 }
36099e8c 64
65 $@ = $exception;
1bc193ac 66}
67
681;
69
70__END__
71
72=head1 NAME
73
6936e902 74DBIx::Class::Storage::TxnScopeGuard - Scope-based transaction handling
1bc193ac 75
76=head1 SYNOPSIS
77
78 sub foo {
79 my ($self, $schema) = @_;
80
81 my $guard = $schema->txn_scope_guard;
82
83 # Multiple database operations here
84
85 $guard->commit;
86 }
87
88=head1 DESCRIPTION
89
90An object that behaves much like L<Scope::Guard>, but hardcoded to do the
fd323bf1 91right thing with transactions in DBIx::Class.
1bc193ac 92
93=head1 METHODS
94
95=head2 new
96
6936e902 97Creating an instance of this class will start a new transaction (by
98implicitly calling L<DBIx::Class::Storage/txn_begin>. Expects a
1bc193ac 99L<DBIx::Class::Storage> object as its only argument.
100
101=head2 commit
102
103Commit the transaction, and stop guarding the scope. If this method is not
48580715 104called and this object goes out of scope (e.g. an exception is thrown) then
6936e902 105the transaction is rolled back, via L<DBIx::Class::Storage/txn_rollback>
1bc193ac 106
107=cut
108
109=head1 SEE ALSO
110
111L<DBIx::Class::Schema/txn_scope_guard>.
112
113=head1 AUTHOR
114
115Ash Berlin, 2008.
116
48580715 117Inspired by L<Scope::Guard> by chocolateboy.
1bc193ac 118
119This module is free software. It may be used, redistributed and/or modified
120under the same terms as Perl itself.
121
122=cut