Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

Propelで作ったモデルのsaveメソッドとトランザクション

個人用メモ&symfony1.0.17での話。
Propel+Creoleで明示的にトランザクションを開始・終了するには

<?php
$con = Propel::getConnection();
try {
    $con->begin();
          :
    $con->commit();
} catch (Exception $e) {
    $con->rollback();
    throw $e;
}
}

な感じで、CreoleのConnection#begin、Connection#commit、Connection#rollbackを使えばOK(Connectionはインターフェース)。
で、Propelで作ったモデルのBaseクラスのsaveメソッドを見ると

<?php
    public function save($con = null)
    {try {
            $con->begin();
            $affectedRows = $this->doSave($con);
            $con->commit();
            return $affectedRows;
        } catch (PropelException $e) {
            $con->rollback();
            throw $e;
        }
    }

のように、ここでトランザクションをcommit/rollbackしているように見える(かなり焦った)。ここでコードを追ってみると、抽象クラスであるConnectionCommonクラスでbegin/commit/rollbackの実装がされている。で、

<?php
abstract class ConnectionCommon {public function commit() 
    {
        if ($this->transactionOpcount > 0) {
            if ($this->transactionOpcount == 1 || $this->supportsNestedTrans()) {
                $this->commitTrans();
            }
            $this->transactionOpcount--;       
        }
    }

な感じで、トランザクションのネストとネストしたトランザクションをサポートしてるかどうかをチェックしている。今使っているのはPostgreSQL8.3系でネストしたトランザクションはサポートされていないはずで、実際に使うPgSQLConnectionクラス(ConnectionCommonクラスのサブクラス)でもsupportsNestedTransメソッドでfalseが返るようになっている。
なので、

<?php
class Relevancy extends BaseRelevancy
{
    public function save($con = null) {
        $con = Propel::getConnection();
        try {
            $con->begin();
            $ret = parent::save($con);

            $answer = $this->getAnswer();
            if ($this->getScore() == 1) {
                $answer->setRelevancyUp($answer->getRelevancyUp() + 1);
            } else {
                $answer->setRelevancyDown($answer->getRelevancyDown() + 1);
            }
            $answer->save($con);

            $con->commit();

            return $ret;
        } catch (Exception $e) {
            $con->rollback();
            throw $e;
        }
    }
}

と書いてもフラット(?)な1つのトランザクションで管理される(ハズ)。