(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…