DBICでトランザクション処理

複数のCRUDを行うとき、例えば100件のデータをinesrtするとき。20件までは成功したけど、残り80件はなんかプログラムエラーで入らなかった、なんてことになったら困るので、一連の処理が全て成功して初めてDBにコミットする、てゆーのがトランザクション
上記みたいな場合以外にも、流すクエリが大量すぎるときに使うと軽くなるかもしれない。
とりあえずDBICでやりましょう。

DBICトランザクション処理するときは、txn_doってメソッドを使う。
http://search.cpan.org/~ash/DBIx-Class/lib/DBIx/Class/Schema.pm#txn_do
ですがな。

  • 基本的な使い方

CatalystDBIx::Class::Storage::DBI::Replicationを使ってるときはこんな感じになる。

my $query = sub {
  $c->model('DBIC::Table')->create({ id => 1,name => 'hoge', });
};

eval { $c->model('DBIC')->schema->storage->write_source->txn_do($txn); };

if ($@) {
  print "err:$@";
}
else {
  print "ok";
}

txn_doは引数にコードリファレンスを取る。それをevalで囲って、そんだけ。
なお、コードリファレンスには別にCRUD以外も入る。

  • あちこちでCRUDしてる場合その1

配列にCRUD文コードリファレンスを好きなだけ入れる。
forでその配列の中身をデリファレンスするコードリファレンスを用意する
それをtxn_doに入れる

push @arr, sub { $c->model('DBIC::Table')->create({ id => 1,name => 'hoge', }); };
push @arr, sub { $c->model('DBIC::Table')->create({ id => 2,name => 'huga', }); };
push @arr, sub { $c->model('DBIC::Table')->create({ id => 3,name => 'fooo', }); };

my $txn = sub { for (@arr) { $_->() }; };

eval { $c->model('DBIC')->schema->storage->write_source->txn_do($txn); };

最初、こう書いてはまった。

my $txn = sub { for (@arr) { $_ }; };

コードリファレンスをデリファレンスしなきゃ、そりゃアドレス返して終わるわ。

  • あちこちでCRUDしてる場合その2

上記のようなことをするのは頭悪い。例えば、main関数にだーっと全部処理書いちゃったときのような。
もし、こんな風にプログラムしてたのであれば・・

main();

sub main {
    transaction_method();
}

こうする。

main();

sub main {
    my $ref = sub { transaction_method(); }:
    eval { $c->model('DBIC')->schema->storage->write_source->txn_do($ref); };
}