Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

DBIx::TransactionManagerのソースを読む

今日はDBIx::TransactionManager-1.091ファイルしかないのでさっくりと。


中では2クラス定義がされていて、DBIx::TransactionManager と DBIx::TransactionManager::ScopeGuard。前者がメインで、後者はスコープガード用のクラス。


txn_begin の中では$dbh->begin_work をしていて、こいつは$dbh->{AutoCommit}を一度無効にして、トランザクションが終わったら自動で$dbh->{AutoCommit} を有効にしてくれるという優れもの。なんだけど、begin_work はネストして呼べないのでそれを可能にするのが TransactionManager のお仕事。active_transactions フィールドがミソになっていて、txn_begin されるごとにここへcaller の情報を貯めていく。このフィールドを見ればネストしているか分かるので、ネストしている場合はbegin_work はしない。


txn_begin へcaller を外から引数として渡せるようになっているのは、TransactionManager のラッパーを作る場合を考慮してのこと。ラッパーを作るときは正しい呼び出し元をcaller パラメータへ渡すようにするとよい。


txn_commit は、ネストの内側で呼ぶと何もしない。ネストの一番外で呼んだときのみ$dbh->commit をする。ネストの途中で txn_rollbackされていると、エラーで落ちてしまう*1。同様にtxn_rollback で実際にrollback が走ってくれるのは、ネストの一番外で呼んだときのみ。

ScopeGuard は基本的にTransactionManager へ処理を委譲する。が、各スコープに対して2度以上commit やrollback をするとtxn_begin の呼び出し回数と矛盾してしまうので、一度しか効果を及ぼさないようにフラグで管理している。rollback も commit もしないでインスタンスが解放される場合には、DESTROY 内でwarning を出しつつ txn_rollback している。

*1:ネストの深ーいとこで誰かがrollback した場合に、一番外側でcommit ではなくrollback を呼ぶ必要があると思うんだけど、commit しちゃあイカンのだってことをどうやって知るのがいいんだろう。