- Fixed Storage::DBI trace such that each bind parameter is quoted on output, separated by commas
- Fixed a couple typos in documentation
Scotty Allen <scotty@scottyallen.com>
- Justin Guenther <jguenther@gmail.com>
+ Justin Guenther <guentherj@agr.gc.ca>
LICENSE
You may distribute this code under the same terms as Perl itself.
sc_
+Justin Guenther <jguenther@agr.gc.ca>
+
=head1 LICENSE
You may distribute this code under the same terms as Perl itself.
=cut
__PACKAGE__->mk_classdata('class_resolver' =>
- 'DBIx::Class::ClassResolver::PassThrough');
+ 'DBIx::Class::ClassResolver::PassThrough');
=head2 connection
=cut
-sub txn_begin { $_[0]->schema_instance->txn_begin }
+sub txn_begin { shift->schema_instance->txn_begin(@_); }
=head2 txn_commit
=cut
-sub txn_commit { $_[0]->schema_instance->txn_commit }
+sub txn_commit { shift->schema_instance->txn_commit(@_); }
=head2 txn_rollback
=cut
-sub txn_rollback { $_[0]->schema_instance->txn_rollback }
+sub txn_rollback { shift->schema_instance->txn_rollback(@_); }
+
+=head2 txn_do
+
+Executes a block of code transactionally. If this code reference
+throws an exception, the transaction is rolled back and the exception
+is rethrown. See txn_do in L<DBIx::Class::Schema> for more details.
+
+=cut
+
+sub txn_do { shift->schema_instance->txn_do(@_); }
{
my $warn;
=head2 Transactions
As of version 0.04001, there is improved transaction support in
-L<DBIx::Class::Storage::DBI>. Here is an example of the recommended
-way to use it:
+L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>. Here is an
+example of the recommended way to use it:
- my $genus = Genus->find(12);
- eval {
- MyDB->txn_begin;
+ my $genus = $schema->resultset('Genus')->find(12);
+
+ my $coderef1 = sub {
+ my ($schema, $genus, $code) = @_;
$genus->add_to_species({ name => 'troglodyte' });
$genus->wings(2);
$genus->update;
- cromulate($genus); # Can have a nested transation
- MyDB->txn_commit;
+ $schema->txn_do($code, $genus); # Can have a nested transation
+ return $genus->species;
+ };
+
+ my $coderef2 = sub {
+ my ($genus) = @_;
+ $genus->extinct(1);
+ $genus->update;
};
- if ($@) {
- # Rollback might fail, too
- eval {
- MyDB->txn_rollback
- };
+
+ my $rs;
+ eval {
+ $rs = $schema->txn_do($coderef1, $schema, $genus, $coderef2);
+ };
+
+ if ($@) { # Transaction failed
+ die "the sky is falling!" #
+ if ($@ =~ /Rollback failed/); # Rollback failed
+
+ deal_with_failed_transaction();
}
-Currently, a nested commit will do nothing and a nested rollback will
-die. The code at each level must be sure to call rollback in the case
-of an error, to ensure that the rollback will propagate to the top
-level and be issued. Support for savepoints and for true nested
+Nested transactions will work as expected. That is, only the outermost
+transaction will actually issue a commit to the $dbh, and a rollback
+at any level of any transaction will cause the entire nested
+transaction to fail. Support for savepoints and for true nested
transactions (for databases that support them) will hopefully be added
in the future.
=head3 Arguments: ($source, \%$attrs)
The resultset constructor. Takes a source object (usually a
-L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see L</ATRRIBUTES>
+L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see L</ATTRIBUTES>
below). Does not perform any queries -- these are executed as needed by the
other methods.
Registers a class which isa ResultSourceProxy; equivalent to calling
- $schema->register_source($moniker, $class->result_source_instance);
+ $schema->register_source($moniker, $component_class->result_source_instance);
=cut
=head2 txn_do
-=head3 Arguments: <coderef>, [@coderef_args]
+=head3 Arguments: <$coderef>, [@coderef_args]
-Executes <coderef> with (optional) arguments <@coderef_args> transactionally,
-returning its result (if any). If an exception is caught, a rollback is issued
-and the exception is rethrown. If the rollback fails, (i.e. throws an
-exception) an exception is thrown that includes a "Rollback failed" message.
+Executes C<$coderef> with (optional) arguments C<@coderef_args>
+transactionally, returning its result (if any). If an exception is
+caught, a rollback is issued and the exception is rethrown. If the
+rollback fails, (i.e. throws an exception) an exception is thrown that
+includes a "Rollback failed" message.
For example,
}
}
-Nested transactions should work as expected (i.e. only the outermost
+Nested transactions work as expected (i.e. only the outermost
transaction will issue a txn_commit on the Schema's storage)
=cut
Calls begin_work on the current dbh.
+See L<DBIx::Class::Schema> for the txn_do() method, which allows for
+an entire code block to be executed transactionally.
+
=cut
sub txn_begin {
my $self = shift;
- $self->dbh->begin_work if $self->{transaction_depth}++ == 0 and $self->dbh->{AutoCommit};
+ $self->dbh->begin_work
+ if $self->{transaction_depth}++ == 0 and $self->dbh->{AutoCommit};
}
=head2 txn_commit
=head2 txn_rollback
-Issues a rollback against the current dbh.
+Issues a rollback against the current dbh. A nested rollback will
+throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
+which allows the rollback to propagate to the outermost transaction.
=cut
my ($sql, @bind) = $self->sql_maker->$op($ident, @args);
unshift(@bind, @$extra_bind) if $extra_bind;
if ($self->debug) {
- my @debug_bind = map { defined $_ ? $_ : 'NULL' } @bind;
- $self->debugfh->print("$sql: @debug_bind\n");
+ my @debug_bind = map { defined $_ ? qq{`$_'} : q{`NULL'} } @bind;
+ $self->debugfh->print("$sql: " . join(', ', @debug_bind) . "\n");
}
my $sth = $self->sth($sql,$op);
croak "no sth generated via sql: $sql" unless $sth;