Zend_Dbでトランザクションの状態管理  2009年6月12日

postgresはトランザクションの多重実行ができないのですが、Zend_DbはPdoを利用したものなので、現在がトランザクション中かどうかを知るすべがありません。

実際のプログラムでは、個別の関数でトランザクションをbegin/commtするケースと、同じ関数を別のトランザクション内部から呼びたいケースがありました。

PHPのpostgres接続関数にはpg_transaction_statusがあって、重宝していたのですが、、、、そこで、Zend_Dbをオーバーライドして、begin/commit/rollBackの状態を管理できるようにしました。

※もっと楽な方法やPdoで対応可能な例があれば教えてください。 m(_ _)m

 

対処は単純でZend_Dbをオーバーライドしたクラスにbegin、commit、rollBackを実行するスタティックメソッドを用意しました。

前回複数の接続を管理できるようにしたクラスを利用します。

 

class Cshe_Db extends Zend_Db
{
    static protected $canTransaction = array();

    static public function factory( $registName = ‘mainDb’)
    {
        try {
            Zend_Loader::loadClass( ‘Zend_Registry’ );
            if ( !Zend_Registry::isRegistered( $registName ) ) {
                $appDatabaseConfig = Zend_Registry::get( ‘database_config’);

                // DB関連設定取得
                $config = $appDatabaseConfig->toArray();
                $adapterName = $config['database'][$registName]['type'];
                unset( $config['database'][$registName]['type']);
                $db = parent::factory( $adapterName, $config['database'][$registName]);

                Zend_Registry::set( $registName, $db);
            } else {
                $db = Zend_Registry::get( $registName);
            }
            return $db;
        }
        catch( Exception $e) {
            throw $e;
        }
    }

    static public function beginTransaction($registName = ‘mainDb’)
    {
        try {

            $db = Ashe_Db::factory($registName);
            $db->beginTransaction();

            // トランザクション開始を記録
            self::$canTransaction[$registName] = false;
        } catch (Exception $e) {
            throw $e;
        }
    }

    static public function commit($registName = ‘mainDb’)
    {
        try {

            $db = Ashe_Db::factory($registName);
            $db->commit();

            // トランザクション終了を記録
            self::$canTransaction[$registName] = true;
        } catch (Exception $e) {
            throw $e;
        }
    }

    static public function rollBack($registName = ‘mainDb’)
    {
        try {

            $db = Ashe_Db::factory($registName);
            $db->rollBack();

            // トランザクション開始を記録
            self::$canTransaction[$registName] = true;
        } catch (Exception $e) {
            throw $e;
        }
    }
}

これで、トランザクションを処理するときにデータベースのAdapterクラスのインスタンスを直接利用せずに

 

Cshe_Db::beginTransaction();

Cshe_Db::commit();

Cshe_Db::rollBack();

を利用することで、以下のようにトランザクションを二重に実行されない(トランザクションがbeginされているときは何もせずに、beginされてないときはトランザクション処理する)関数が作れます。

function aaaa()
{
    // トランザクションが未開始の場合開始
    if ($isTransaction = Cshe_Db::isTransaction()) {
        // トランザクション未開始
        Cshe_Db::beginTransaction();
    }
   
    // いろいろな処理
   
    // この関数でトランザクションが開始されている場合はコミット
    if($isTransaction) {
        Ashe_Db::commit();
    }
}

このエントリをはてなブックマークに登録 このエントリをBuzzurlにブックマーク Yahoo!ブックマークに登録 このエントリをlivedoorクリップに登録 Deliciousにブックマーク

コメントを投稿