元フリーエンジニアライフ

Ruby on Rails とか MovableType とかAWSやってるフリーランスウェブエンジニアの記録でした。現在は法人成りしてIT社長。

MT::Object::remove() でトランザクションが効かない件について

バグか仕様かわかりませんが嵌まったのでメモ。

こんなかんじでトランザクション使えますが、remove()の場合、begin_workで立てたはずのトランザクションを使うぞ!的なフラグを無視しやがるようです。

MT::Object でのトランザクション(Rollback / Commit) - フリーエンジニアライフ

my $entry = MT->model( 'entry' )->load();

$entry->begin_work;

$entry->remove();          # DELETE ...

$entry->rollback();        # だが何度でもよみがえ…らない!

先の記事で触れたとおり、Data::ObjectDriver::BaseObjectremove()などを使っている限り、これでDELETE文の前に$driver->begin_workトランザクションが開始されるはずなのです。

lib/MT/Object.pm を覗いてみると、remove()についてはオーバーライドで親クラスをすっ飛ばしてました。 これでは$driver->begin_work呼ばれません。

lib/MT/Object.pm

sub remove {
    my $obj = shift;
    my (@args) = @_;
    if ( !ref $obj ) {
        for my $which (qw( meta summary )) {
            my $meth = "remove_$which";
            my $has  = "has_$which";
            $obj->$meth(@args) if $obj->$has;
        }
        $obj->remove_scores(@args) if $obj->isa('MT::Scorable');
        MT->run_callbacks( $obj . '::pre_remove_multi', @args );
        return $obj->driver->direct_remove( $obj, @args );
    }
    else {
        return $obj->driver->remove( $obj, @args );
    }
}

回避方法ですが、とりあえずexists()あたりを使っておけば動くようです。

my $entry = MT->model( 'entry' )->load();

$entry->begin_work;
if ( $entry->exists() ) {      # auto_commit=0
    $entry->remove();          # DELETE ...

    $entry->rollback();        # rollback & auto_commit=1
}