CakePHPの公式サイトを確認すると、
モデル内で以下のようにかけるらしい。
<?php $dataSource->begin(); if (/*すべて成功*/) { $dataSource->commit(); } else { $dataSource->rollback(); }
でも今回はコントローラーでかけたい。
ということで、トランザクション管理用のモデルを作った。
<?php App::uses('AppModel', 'Model'); class TransactionManager extends AppModel { public $useTable = false; public function begin(){ $dataSource = $this->getDataSource(); $dataSource->begin($this); return $dataSource; } public function commit($_dataSource){ $_dataSource->commit(); } public function rollback($_dataSource){ $_dataSource->rollback(); } }
---追記 2015/10/27 ---
上記のコードについてコメント欄で
$_dataSource->commit();
$_dataSource->rollback();
に以下のように $this を付けないとエラーになるとの指摘を受けました。
$_dataSource->commit($this);
$_dataSource->rollback($this);
その後のコメントで、$thisを付けなくても大丈夫とのことでした。
完全な勘ですが、begin() で $this を渡しているので、
$dataSource ではそれが保持されていると思います。
なので、commit() に $this を指定しなくても動作すると思います。
むしろ、commit() に $this を指定すると、コミット対象の $dataSource が
上書きされそう・・・。
---------------------
こーゆーモデルを作ればController側で以下のように使える。
---追記 2014/12/16 ---
コメント欄で
$transaction = $this->TransactionManager->begin();
のスコープについてご指摘をいただいたので修正しました。
---------------------
<?php $this->loadModel('TransactionManager'); $transaction = $this->TransactionManager->begin(); try{ //モデルの処理を書く。 //ここで複数のモデルを使っても1つのトランザクションで管理されるので問題ない。 $this->TransactionManager->commit($transaction); }catch(Exception $e){ $this->TransactionManager->rollback($transaction); }
$this->loadModel('TransactionManager'); の部分は $uses で定義してもいい。
トランザクション用のモデルを作らずに AppModel.php に作っても動くが、
以下の様な書き方になる。
メソッド名とかモデル名はテキトーです。
<?php $this->User->begin(); $this->Point->insertData(100); $this->User->insertData(100); $this->User->commit();
User, Point という複数のモデルを使っているが、
トランザクションは User モデルでスタートしている。
一応、UserとPointにトランザクションが効くが、
なんかイメージつかない。
Userのみトランザクション対象に思える。
ということで、トランザクション用のモデルを作ったほうがいいかな。