(1.5)の続き
(本記事は書きかけで随時更新しております。)
ネストしたトランザクションの挙動を見ていく。
なお、MariaDBはネストしたトランザクション(BEGIN始まり)はサポートしていない。
ConnectionManager のbeginを利用してトランザクションを開始し、execute()メソッドを使用
ordersに1レコード挿入後、再度トランザクションを開始し、order_detailsに2レコード挿入する
protected function nestExecuteSuccess() : void {
$this->io->info("ネストしたトランザクションのテスト。\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();
$successOrder = 'fail';
$successOrderDetail = 'fail';
try{
$this->io->out("ordersに挿入(成功SQL実行)");
$ret = $connection->execute(
'INSERT into orders (order_name) values(?)',
["name1"]
);
$connection->begin();
try{
$this->io->out("order_detailsに挿入(成功SQL実行)");
$ret = $connection->execute(
'INSERT into order_details (order_id,sub_order_name) values(?,?)',
[1,"sub_name1"]
);
$ret = $connection->execute(
'INSERT into order_details (order_id,sub_order_name) values(?,?)',
[1,"sub_name2"]
);
$connection->commit();
$successOrderDetail = 'success';
}catch(Exception $ex){
$this->io->error('Exception in orderDetails 発生');
$this->io->error($ex->getMessage());
$connection->rollback();
}
$connection->commit();
$successOrder = 'success';
}catch(Exception $ex){
$this->io->error('Exception in orders 発生');
$this->io->error($ex->getMessage());
$connection->rollback();
}finally{
}
$this->io->hr();
$ordersTable = $this->fetchTable('Orders');
$orderRowCount = $ordersTable->find()->count();
$orderDetailsTable = $this->fetchTable('OrderDetails');
$orderDetailRowCount = $orderDetailsTable->find()->count();
$this->io->warning('Ordersのレコード数:'.$orderRowCount);
$this->io->warning('OrderDetailsのレコード数:'.$orderDetailRowCount);
$this->io->warning('$successOrder = '.$successOrder);
$this->io->warning('$successOrderDetail = '.$successOrderDetail);
}
[dev]$ bin/cake transaction nestExecuteSuccess ネストしたトランザクションのテスト。 最初にtruncate table 実行する。 ------------------------------------------------------------------------------- ordersに挿入(成功SQL実行) order_detailsに挿入(成功SQL実行) ------------------------------------------------------------------------------- Ordersのレコード数:1 OrderDetailsのレコード数:2 $successOrder = success $successOrderDetail = success
CakePHPのqueryログ。
debug: connection= role=write duration=5.4 rows=0 truncate table orders;
debug: connection= role=write duration=52 rows=0 truncate table order_details;
debug: connection= role= duration=0 rows=0 BEGIN
debug: connection= role=write duration=0.3 rows=1 INSERT into orders (order_name) values('name1')
debug: connection= role=write duration=0.1 rows=1 INSERT into order_details (order_id,sub_order_name) values('1','sub_name1')
debug: connection= role=write duration=0 rows=1 INSERT into order_details (order_id,sub_order_name) values('1','sub_name2')
debug: connection= role= duration=0 rows=0 COMMIT
結果:トランザクションがネストしていない。ただし生のSQLと異なり、2回目のbeginは強制commitされず無視される。
savepointが使われていない。
さらに、ordersへの挿入をorder_detailsの後ろに移動してみる。
$connection->begin();
$successOrder = 'fail';
$successOrderDetail = 'fail';
try{
$this->io->out("ordersに挿入(成功SQL実行)");
$connection->begin();
try{
$ret = $connection->execute(
'INSERT into order_details (order_id,sub_order_name) values(?,?)',
[1,"sub_name1"]
);
$ret = $connection->execute(
'INSERT into order_details (order_id,sub_order_name) values(?,?)',
[1,"sub_name2"]
);
$connection->commit();
$successOrderDetail = 'success';
}catch(Exception $ex){
$this->io->error('Exception in orderDetails 発生');
$this->io->error($ex->getMessage());
$connection->rollback();
}
$this->io->out("order_detailsに挿入(成功SQL実行)");
$ret = $connection->execute(
'INSERT into orders (order_name) values(?)',
["name1"]
);
$connection->commit();
$successOrder = 'success';
}catch(Exception $ex){
$this->io->error('Exception in orders 発生');
$this->io->error($ex->getMessage());
$connection->rollback();
}finally{
}
[dev]$ bin/cake transaction nestExecuteSuccess ネストしたトランザクションのテスト。 最初にtruncate table 実行する。 ------------------------------------------------------------------------------- order_detailsに挿入(成功SQL実行) ordersに挿入(成功SQL実行) ------------------------------------------------------------------------------- Ordersのレコード数:1 OrderDetailsのレコード数:2 $successOrder = success $successOrderDetail = success
debug: connection= role= duration=0 rows=0 BEGIN
debug: connection= role=write duration=0.2 rows=1 INSERT into order_details (order_id,sub_order_name) values('1','sub_name1')
debug: connection= role=write duration=0 rows=1 INSERT into order_details (order_id,sub_order_name) debug: connection= role=write duration=0 rows=1 INSERT into orders (order_name) values('name1')
debug: connection= role= duration=0 rows=0 COMMIT
結果:内側のcommitも無視されていることがわかる。
savepointが使われていない。→ 別記事にするが、意図的に有効にしなければ効かない。
ordersに1レコード挿入後、再度トランザクションを開始し、order_detailsに2レコード挿入するが、子トランザクション内でrollback() する。
protected function nestExecuteRollback() : void {
$this->io->info("ネストしたトランザクションのテスト。\n最初にtruncate table 実行し、子トランザクション内でrollback()を実行。");
$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();
$successOrder = 'fail';
$successOrderDetail = 'fail';
try{
$this->io->out("ordersに挿入(成功SQL実行)");
$ret = $connection->execute(
'INSERT into orders (order_name) values(?)',
["name1"]
);
$connection->begin();
try{
$this->io->out("order_detailsに挿入(成功SQL実行)");
$ret = $connection->execute(
'INSERT into order_details (order_id,sub_order_name) values(?,?)',
[1,"sub_name1"]
);
$ret = $connection->execute(
'INSERT into order_details (order_id,sub_order_name) values(?,?)',
[1,"sub_name2"]
);
$connection->rollback();
$successOrderDetail = 'force rollback';
}catch(Exception $ex){
$this->io->error('Exception in orderDetails 発生');
$this->io->error($ex->getMessage());
$connection->rollback();
}
$connection->commit();
$successOrder = 'success';
}catch(Exception $ex){
$this->io->error('Exception in orders 発生');
$this->io->error($ex->getMessage());
$connection->rollback();
}finally{
}
$this->io->hr();
$ordersTable = $this->fetchTable('Orders');
$orderRowCount = $ordersTable->find()->count();
$orderDetailsTable = $this->fetchTable('OrderDetails');
$orderDetailRowCount = $orderDetailsTable->find()->count();
$this->io->warning('Ordersのレコード数:'.$orderRowCount);
$this->io->warning('OrderDetailsのレコード数:'.$orderDetailRowCount);
$this->io->warning('$successOrder = '.$successOrder);
$this->io->warning('$successOrderDetail = '.$successOrderDetail);
}
[dev]$ bin/cake transaction nestExecuteRollback ネストしたトランザクションのテスト。 最初にtruncate table 実行し、子トランザクション内でrollback()を実行。 ------------------------------------------------------------------------------- ordersに挿入(成功SQL実行) order_detailsに挿入(成功SQL実行) ------------------------------------------------------------------------------- Ordersのレコード数:0 OrderDetailsのレコード数:0 $successOrder = success $successOrderDetail = force rollback
debug: connection= role= duration=0 rows=0 BEGIN
debug: connection= role=write duration=1.8 rows=1 INSERT into orders (order_name) values('name1')
debug: connection= role=write duration=0.1 rows=1 INSERT into order_details (order_id,sub_order_name) values('1','sub_name1')
debug: connection= role=write duration=0.1 rows=1 INSERT into order_details (order_id,sub_order_name) values('1','sub_name2')
debug: connection= role= duration=0 rows=0 ROLLBACK
結果:rollback() は、親のbegin() に対応してしまっている。

