DBICでトランザクション処理
複数のCRUDを行うとき、例えば100件のデータをinesrtするとき。20件までは成功したけど、残り80件はなんかプログラムエラーで入らなかった、なんてことになったら困るので、一連の処理が全て成功して初めてDBにコミットする、てゆーのがトランザクション。
上記みたいな場合以外にも、流すクエリが大量すぎるときに使うと軽くなるかもしれない。
とりあえずDBICでやりましょう。
- txn_do
DBICでトランザクション処理するときは、txn_doってメソッドを使う。
http://search.cpan.org/~ash/DBIx-Class/lib/DBIx/Class/Schema.pm#txn_do
ですがな。
- 基本的な使い方
CatalystとDBIx::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); }; }