Transactions between promises
yuriy-zhilovets2 opened this issue · comments
Transactions do not work if they are splitted between promises like this:
my $tx;
$tx = $db->begin;
$db->query_p("INSERT ...")->then(sub
{
$db->query_p("DELETE ...");
})->then(sub {
$tx->commit;
});
Apparently, queries from then-blocks execute on different connections.
I think that documentation must reflect this limitation.
I don't believe your statement is correct. There's nothing that changes the dbh
attribute on the database object. Please provide a complete failure test.
Hi, jhthorsen!
I wrote example, which is very similar to the case in a real project:
#!/usr/bin/perl
use warnings;
use strict;
use 5.010;
use utf8;
use Mojo::mysql;
my $mysql = Mojo::mysql->new({
dsn => 'dbi:mysql:host=localhost;database=foo',
username => 'root',
password => '123456',
options => { RaiseError => 1, PrintError => 0 }
});
my $tx = $mysql->db->begin;
$mysql->db->query_p('CREATE TABLE bar (value int(11))')
->then(sub {
return $mysql->db->query_p('CREATE TABLE baz (value int(11))')
})
->then(sub {
return fill(10, 20)
})
->then(sub {
$tx->commit;
})
->catch(sub {
undef $tx;
})
->wait;
sub fill {
my $count = shift;
my $value = shift;
return $mysql->db->query_p('SELECT COUNT(*) AS total FROM bar WHERE value = ?', $value)
->then(sub {
my $res = shift;
my $total = $res->hash->{total};
$res->finish;
if ($total < $count) {
return $mysql->db->insert_p('bar', { value => $value })
->then(sub {
return fill($count, $value)
});
} else {
return $mysql->db->insert_p('bazz', { value => $value });
}
})
}
As you can see, I have specifically made a mistake in the table name (bazz instead of baz) and I expected a rollback of the transaction, but it didn't happen. After execution all tables are still alive and table 'bar' has all inserted rows.
I don't see how your example is valid, since every call to $mysql->db
might create a new connection. If you want to reuse the same connection, then you have to store the value from $mysql->db
. Like this:
my $db = $mysql->db;
my $tx = $db->begin;
$db->query_p('CREATE TABLE bar (value int(11))')->then(sub {
return $db->query_p('CREATE TABLE baz (value int(11))')
})->then(sub {
$tx->commit;
})->catch(sub {
warn "ERR! $_[0]";
undef $tx;
undef $db;
})
Also, I'm not sure how good MySQL handles transactions when doing ALTER TABLE
. I would recommend to double check the documentation for the MySQL server version you're using.
My bad. I stored database handle and now transaction works fine. Sorry and thanks a lot.