cakePHP覚書#2
ちょっと複雑なデータ更新が必要になってきたので、トランザクションを調べることにした。
ひとつのテーブルで更新と追加が同時発生、他のテーブルでも同様という風に二つのテーブルにまたがる処理ですが
アソシエーションでは定義できないようなもの。
まずMySQLのテーブルがMyISAMだとロールバックしても効かないので使えない。InnoDBに変更が必要となる。
show table status;
で現状の確認をする。MyISAMで作っている既存テーブルもInnoDBに変更可能。
変更するには、phpMyAdminであればテーブルの「操作」で「ストレージエンジン」を「InnoDB」に変更して実行押すだけ。
alter table 'xxxx' engine=InooDB;
が実行された。もちろんコマンドラインから、これを打ってもOKです。
さてさて、begin() commit() rollback() をどこで定義しておくか。
必要なテーブルのモデルだけで定義しておいてもいいけど面倒ですね。思い切ってapp_modelに書いとけば全部のモデルで継承してくれますから、これでいいかな。
いつものように、cake以下は触らないお約束で、cake/libs/modelのなかのapp_model.phpをapp/models以下にコピーしておいて追加します。
function begin() { $dbs = & ConnectionManager::getDataSource($this->useDbConfig); $dbs->begin($this); } function commit() { $dbs = & ConnectionManager::getDataSource($this->useDbConfig); $dbs->commit($this); } function rollback() { $dbs = & ConnectionManager::getDataSource($this->useDbConfig); $dbs->rollback($this); }
これで、モデルの関数になるのでモデル名->begin()とかで使えます。
2つのモデルを同時更新なら
ModelA->begin(); ModelB->begin(); 処理ほにゃらら なんか問題あったら ModelA->rollback(); ModelB->rollback(); エラー無く終了。 ModelA->commit(); ModelB->commit();
こんな具合かな。それとsavaAllを使うときの注意もあった。saveAllの外側でトランザクション開始していてもループの途中でコミットされちゃうみたいです。対策としてはパラメータを追加しておくこと。
ModelA->saveAll($datas ,array('atomic'=>false);
こんなおまじないが必須だ。
追記:どうもModelA ModelB両方にbegin() rollback() commit()を行わなくても、ModelAだけやっておけば、両方に効力があるという記述を発見。まだ未検証です。
追記:検証しました。
実行されたSQLも確認しましたが、どれかひとつのモデルでトランザクション操作しておけばOKです。