[s2container-php5:34] S2Dao.PHP5+MySqlでのPDOトランザクションについて

Eishi Kuroda kuroda @ jetsetrecords.net
2006年 6月 24日 (土) 20:52:26 JST


こんにちは。

先日からS2Dao.PHP5で色々試しているのですが、
下記環境でPDOトランザクションを利用しようとして問題が発生し困っています。

s2container.php5-1.1.0
s2dao.php5-1.1.0-rc3
MySQL 4.1.20
PHP 5.1.2
windows 2000


例えばMemberEntryServiceを下記のように設定します。
executeメソッドで、memberDaoを使って挿入処理を行います。

<component name="service" class="MemberEntryServiceImpl">
    <aspect pointcut="execute">pdo.requiredTx</aspect>
    <property name="memberDao">memberDao</property>
</component>

<component name="memberDao" class="MemberDao">
    <aspect>dao.interceptor</aspect>
</component>

pdo.diconは下記の通りです。

<components namespace="pdo">
    <component name="dataSource" class="S2Container_PDODataSource">
        <property name="dsn">"mysql:host=localhost;dbname=test"</property>
        <property name="user">"root"</property>
        <property name="password">"test"</property>
        <property name="option">
            array(PDO::ATTR_ORACLE_NULLS => PDO::NULL_EMPTY_STRING,
                     PDO::ATTR_AUTOCOMMIT => false);
        </property>
    </component>

    <component name="requiredTx" class="S2Dao_RequiredInterceptor" />
    <component name="requiresNewTx" class="S2Dao_RequiresNewInterceptor" />
    <component name="mandatoryTx" class="S2Dao_MandatoryInterceptor" />
    <component name="notSupportedTx" class="S2Dao_NotSupportedInterceptor" />
</components>


この状態で、MemberEntryServiceImplからexecuteしてみると、

exception 'PDOException' with message 'There is already an active transaction' in 
c:\www\test\lib\S2Dao\S2Dao\S2Dao_AbstractTxInterceptor.class.php:45

とエラーとなってしまいます。
 (<aspect pointcut="execute">pdo.requiredTx</aspect>を外して、
PDO::ATTR_AUTOCOMMIT => trueとすれば挿入できます。)

S2Dao_AbstractTxInterceptor
および
S2Dao_RequiredInterceptor
を確認してみると、
S2Dao_AbstractTxInterceptorのhasTransactionメソッドで、
下記のように処理しているようです。

        try {
            $this->connection->beginTransaction();
        } catch(Exception $e){
            $this->begin = true;
            return true;
        }

S2Dao_RequiredInterceptorのinvoke側では、
下記のようになっています。

        if (!$this->hasTransaction()) {
            $this->begin();        
            $began = true;
        }

hasTransaction()を呼び出すと、
beginTransaction()によってトランザクションが開始され、
S2Dao_RequiredInterceptor側で更にbegin()としているので、
ここでエラーになるようなのです。

そこで、とりあえずinvokeを下記の様にしてみたところ、
どうやら上手く動作しているようなのですが、
これで問題ないものなのでしょうか?

        if (!$this->hasTransaction()) {
            if (!$this->hasTransaction()) {
                $this->begin();    //多分ここを通過することは無い
             }
            $began = true;
        }

S2Dao_RequiredInterceptorを書き換えるものなんなので
何か他に良い解決方法があるのかも知れないと思うのですが、どうでしょうか?

では、よろしくお願いいたします。

黒田映史



S2Container-PHP5 メーリングリストの案内