排他処理
PHPではWebアプリケーションを作ることが大半だと思います。その中でデータ更新するシステムを作られる場合、考えなければ
ならないことは、不特定多数のユーザーが更新を行うことです。
有名なもではファイルロックなどでしょうか。また、DBの場合では
トランザクション機能で対応するものなどが挙げられると思います。
この排他処理はかなり重要な仕組みだと思います。しかし、予算
などの都合で、一番最初に削られてしまう機能でもあります。
その原因は排他処理の重要性をクライアントが勘違いしている点に
あると思います。
「規模が小さいから同時にアクセスする人もいないし……」
この同時の中身が一瞬の処理と捕らえている人がいます。
カウンタなどでは読み書き処理が重なる一秒以下の処理もあるでしょうが
以下に示す例は結構あり得るものです。
排他処理の重要性を考えてみました。
例ではオフィス用のグループウェアを想定してます。
排他処理を考える
![]() |
時間13時00分 藤井さん(仮名)がAプロジェクトの見積もりを修正しています。 「Aプロジェクト」見積もり入力フォームが表示されています。 |
![]() |
時間13時03分 作業中の藤井さんに電話が入りました。 まだ、「Aプロジェクト」見積もり入力フォームが表示されています。 |
![]() |
時間13時05分 田中さん(仮名)がAプロジェクトの見積もりを修正しようと入力フォームを開きました。 「Aプロジェクト」見積もり入力フォームが表示されています。 時間13時07分 田中さんがAプロジェクトの見積もりの修正が完了しました。 「Aプロジェクト」見積もりの修正完了が表示されました。 |
![]() |
時間13時09分 電話が終わった藤井さんが再びAプロジェクトの見積もりを修正し、完了しました。 「Aプロジェクト」見積もりの修正完了が表示されました。 |
|
排他処理を行っていない場合、田中さんが修正した見積もりに藤井さんが上書きしてしまいます。 田中さんは藤井さんの修正中に作業をしています。この時田中さんが確認した見積もりは藤井さんが 修正する前のものです。 修正内容が同じ場合や藤井さんの修正が正しければ問題有りませんが、そうとも限りません。 そこでアプリケーション側で以下のような警告を出すなど排他処理をサポートしなければなりません。 「Aプロジェクト」が田中さんにより更新されています。 |
|
排他処理の方法
| 排他処理の方法 | |||||
|
排他処理の方法としてはセッションの利用やフラグを用いるなど 色々あると思います。 私がよく使う方法はテーブルにタイムスタンプを用意する方法です。 修正前のタイムスタンプを持ちまわし、実際に更新をかける際にテーブル にあるタイムスタンプと持ちまわした値が異なる場合に処理を発生させる 方法です。 同時に複数の人が修正できない様にロックする方法もありますが修正途中で ブラウザが落ちてしまう場合など中断することを考えなければならず 面倒くさいと言う点からも上書きの際、警告出す方法を使ってしまいます。 排他処理は使う人間の判断に任すのが一番楽です。 |
|||||
CREATE TABLE project_tbl ( id INTEGER NOT NULL, avail INTEGER DEFAULT 1, name VARCHAR(64) NOT NULL, account INTEGER NOT NULL, modify TIMESTAMP NOT NULL, number INTEGER, PRIMARY KEY (id) ) |
|||||
| CID | 項目名 | 型名 | NOT NULL | 初期値 | キー |
| 0 | id | INTEGER | notnull | PRIMARY | |
| 1 | avail | INTEGER | 1 | ||
| 2 | name | VARCHAR(64) | notnull | ||
| 3 | account | INTEGER | notnull | ||
| 4 | modify | TIMESTAMP | notnull | ||
| 5 | number | INTEGER | |||
/* 最終更新時間の取得 */ $query = "SELECT modify FROM project_tbl WHERE id=16"; $modify = $objdb->getOne($query); if (DB::isError($modify)){ return false; } /* 持ち回していた更新時間と比較 */ if ($_POST['modify'] != $modify){ echo "修正中に他の方により更新されています。"; return false; } /* 更新処理 */ $now = date('Y-m-d H:i:s',time()); $query = "UPDATE project_tbl SET number='{$number}', account='{$account}', modify='{$now}' WHERE id=16"; $result = $objdb->query($query); if (DB::isError($result)){ return false; } echo "修正が完了しました。"; |
|||||
![]() |
時間13時09分 電話が終わった藤井さんが再びAプロジェクトの見積もりを修正し、完了しました。 「Aプロジェクト」が田中さんにより更新されています。 藤井さんが修正内容を判断して改めて更新を行います。 |




