いつもお世話になっております。
・目的
未使用のレコードを1件取得し、使用したレコードを使用済みに更新する
・不安点
排他制御が出来ているか不安。同時に処理が走った時にエラーにならないかどうか
giftsテーブル
+----+----------------+------------------+
| id | condition_code | number |
+----+----------------+------------------+
| 1 | 1 | 1234567890123456 |
| 2 | 1 | 2234567890123456 |
| 3 | 1 | 3234567890123456 |
| 4 | 1 | 4234567890123456 |
| 5 | 1 | 5234567890123456 |
+----+----------------+------------------+
PHP
1try { 2 $dataSource = $this->getDataSource(); 3 $dataSource->begin(); 4 $options['conditions'] = [ 5 'Gift.condition_code' => 1, 6 ]; 7 $options['fields'] = [ 8 'Gift.id', 9 'Gift.number', 10 ]; 11 12 $results = $this->Gift->find('first', $options); 13 $saveFields = [ 14 'id' => $results ['Gift']['id'], 15 'condition_code' => 2, 16 ]; 17 18 $this->Gift->set($saveFields); 19 20 if ($this->Gift->save() === false) { 21 throw new DbException(['label' => 'Failed to save line_gifts', 'description' => serialize($results ['Gift']['id'])]); 22 } 23 $dataSource->commit(); 24 25 } catch (DbException $e) { 26 $dataSource->rollback(); 27 28 throw new FatalErrorException($e->getAttributes()); 29 }
行っていることはまずは未使用状態のnumberを取得(使用はcondition_code=1未使用は2)
そのIDを条件にcondition_codeを2に更新すると言う単純な作業ではあるのですが、
これだと同時にアクセスがあった際に同じnumberを最初のfindで取得してしまう可能性があるのではないかと懸念しています。実際はトランザクション内に外のDBに格納する処理も走っているので不安です。
また2回DBにアクセスしているので、出来れば1回にまとめたいのですが、
SQL
1UPDATE gifts SET condition_code=2 where id= (SELECT id FROM (SELECT id FROM gifts WHERE condition_code=1 ORDER BY id ASC LIMIT 1) as tmp FOR UPDATE);
おそらくこのSQLであれば私が行いたいことと排他制御を考えたSQLだと思うのですが、これを実現するcakephpの書き方がわからず困っています。
質問としましては
・上記のコードだとやはり複数アクセスがあった時に問題は起こるでしょうか?またその対策が何かありましたらご教授ください。
・上記のSQLを実行出来るcakephpの書き方をご教授ください。
長くなりましたがよろしくお願いします。
回答1件
あなたの回答
tips
プレビュー