質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

3回答

7204閲覧

CakePHP2.x 系の トランザクション処理はどこに書くのが正しいのか?

ochame

総合スコア12

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

1グッド

0クリップ

投稿2016/12/14 11:11

タイトルのとおりなのですが、
Save メソッドを実行する際に Controller 側から Modelに書いた Save 用のメソッドを呼び出して保存をしています。

その時に transaction 処理は controller 側に書くのが正しいのか、
それとも Model 側で処理を書くのが正しいのか。

どっちでも良いのかもしれないですが、よく分かってないです。
以下がスクリプトの例になります。(間違ってたらどうしよう。。。)


パターン1

▼Controller

if ($this->request->is('post')) { try { $this->Hoge->begin(); if ($this->Hoge->insert($this->request->data)) { if ($this->Fuga->insert($this->request->data)) { $this->Hoge->commit(); $this->redirect('/'); } else { throw new Exception('error'); } } else { throw new Exception('error'); } } } catch (Exception $e) { $this->Hoge->rollback(); }

▼Model

public function insert($data) { $this->create(); if ($this->save($data)) { $result = true; } $result = false; } return $result; }

パターン2

▼Controller

if ($this->request->is('post')) { if ($this->Hoge->insert($this->request->data)) { if ($this->Fuga->insert($this->request->data)) { $this->redirect('/'); } }

▼Model

public function insert($data) { try { $model->begin(); $model->create(); if ($model->save($data)) { $result = true; $model->commit(); } else { throw new Exception('Error'); } } catch (Exception $e) { $model->rollback(); } return $result; }

※パターン2の場合、2回目のsave時のデータが一回目のデータと紐づく場合
2回目がこけてRollbackされたら整合性が合わなくなるので、
本来のソースでは、bigin と commit のタイミングを調整しています。
ただ、そもそもそれも正しいのか分からないのですが。。。

どなた様か、こういう場合のデザインパターンはこれやー!っていうのがあればごご教示お願いいたします。

KiyoshiMotoki👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

複数のモデルそれぞれに保存するならパターン1のControllerでいいと思いますよ。
なるべくモデル内でやりたいなら、Hogeモデル内のinsert関数内で、Fugaモデルのsaveも一緒にやってもいいと思います。

処理的にもパターン1は、戻り値とExceptionの両方を見ていて、問題ないと思います。
モデルのinsert関数内でsave()の戻り値がfalseならExceptionを投げるほうがよりスマートかもしれませんけど

Controller

php

1if ($this->request->is('post')) { 2 $this->Hoge->begin(); 3 try { 4 $this->Hoge->insert($this->request->data); 5 $this->Fuga->insert($this->request->data); 6 $this->Hoge->commit(); 7 $this->redirect('/'); 8 } catch (Exception $e) { 9 $this->Hoge->rollback(); 10 } 11}

Model

php

1public function insert($data) { 2 $this->create(); 3 if(!$this->save($data)) { 4 throw new InternalErrorException('error'); 5 } 6}

投稿2016/12/14 12:35

編集2016/12/14 20:50
popobot

総合スコア6586

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Controllerがベストだと思います。
複雑なビジネスロジックになるとモデルのアソシエーションだけでは整合性が保てないケースがあると思います。例えば、受注データを元に在庫を引き当てて出荷データを作るとか。受注データの更新、在庫データの更新、出荷データの作成などこれ一連で1トランザクションとかざらにあると思います。
こういう場合、DBテーブルベースのモデル内でトランザクション処理をするのは不可能ではないですが、かなり厄介です。
しかし、詰め込み過ぎるとControllerの可読性が悪くなる場合もあるので、ビジネスロジックだけを持ったモデルを作成して、その中でトランザクション処理を書くという方法もあると思います。

投稿2016/12/20 14:06

tkymgr

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

コントローラー内でやるのが確実かと思います。

複数の場合面倒なので、アソシエーションが組まれたModelをまとめてbegin()/commit()/rollback()してくれるメソッドをmodel.phpあたりに作ってしまえば楽かもしれません。
そのうえで、保存処理についても、一度に複数のアソシエーションモデルのデータを保存できるsaveAssociated()メソッドを使ったほうがよりスマートな気がします。

投稿2016/12/14 17:00

CodeLab

総合スコア1939

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問