MariaDB とCakePHP5でのトランザクションの実験(2)

この記事は約6分で読めます。

(1)の続きとして

大まかに二つのシナリオがある。

  • 一つのトランザクション中で、2つのSQLを発行する動作の際、2番目のSQLがエラーとなった場合の挙動
  • ネストしたトランザクションの挙動
    MariaDBはネストしたトランザクション(BEGIN始まり)はサポートしていない。

ConnectionManager のbeginを利用してトランザクションを開始し、execute()メソッドを使用

ordersに1レコード挿入後、再度トランザクションを開始し、order_detailsに1レコード挿入する

        $this->io->info("テスト 開始");
        $this->io->out("ネストしたトランザクション。\n最初にtruncate table 実行する。");
        $this->io->hr();
        /** @var Cake\Database\Connection */
        $connection = ConnectionManager::get('default');
        $ret = $connection->execute( 'truncate table orders;' );
        $ret = $connection->execute( 'truncate table order_details;' );
        $connection->begin();
        $success = false;
        try{
            $this->io->out("ordersに挿入(成功SQL実行)");
            $ret = $connection->execute(
                'INSERT into orders (order_name) values(?)',
                ["name1"]
            );

            $connection->begin();
            try{
                $ret = $connection->execute(
                    'INSERT into order_details (order_id,sub_order_name) values(?,?)',
                    [1,"sub_name1"]
                );
                $connection->commit();
            }catch(Exception $ex){
                $this->io->error('Exception in orderDetails 発生');
                $this->io->error($ex->getMessage());
                $connection->rollback();
            }
            $success = true;
        }catch(Exception $ex){
            $this->io->error('Exception in orders 発生');
            $this->io->error($ex->getMessage());
            $connection->rollback();
        }finally{
            $connection = null;
        }

        $this->io->hr();
        $ordersTable = $this->fetchTable('Orders');
        $orderRowCount = $ordersTable->find()->count();
        $orderDetailsTable = $this->fetchTable('Orders');
        $orderDetailRowCount = $orderDetailsTable->find()->count();
        $this->io->warning('Ordersのレコード数:'.$orderRowCount);
        $this->io->warning('OrderDetailsのレコード数:'.$orderDetailRowCount);
        if ( $success){
            $this->io->warning('commit success');
        }else{
            $this->io->warning('commit fail');
        }
bin/cake transaction test
トランザクションのテスト開始
ネストしたトランザクション。
最初にtruncate table 実行する。
-------------------------------------------------------------------------------
ordersに挿入(成功SQL実行)
-------------------------------------------------------------------------------
Ordersのレコード数:1
OrderDetailsのレコード数:1
commit success

結果:正常

order_details 挿入後、rollback

//子トランザクションの $connection->commit();
$connection->rollback(); //に変更
bin/cake transaction test3
トランザクションのテスト開始
ネストしたトランザクション。
最初にtruncate table 実行する。
-------------------------------------------------------------------------------
ordersに挿入(成功SQL実行)
-------------------------------------------------------------------------------
Ordersのレコード数:0
OrderDetailsのレコード数:0
commit success

結果:子トランザクション開始の、$connection->begin(); で、親トランザクションが自動的にコミットされず、親トランザクションもロールバックされている。
CakePHPのconnection オブジェクト内では、既にbeginが発行されてる場合、SAVEPOINTが使われていてネストを実現しているようだ。

to be continued…

タイトルとURLをコピーしました