具体的には、下記のようなことをやりたいのですが、2の処理でPHPが終了すると同時にトランザクションが終了し、排他制御も終了されてしまいます。
1.物件を検索する
2.物件の修正ボタン押下 ←ここでトランザクション&排他制御開始
3.ユーザーに修正させる ←手入力させる他、住所や交通機関、オーナー等を別途検索&物件情報にセットしたい
4.物件の登録ボタン押下 ←ここでコミット&排他制御の終了
5.修正完了
コマンドプロンプト上で直接MySQLに対してテストした時は、トランザクションおよび排他制御が思い通りに動いたのですが、PHPで実現することが出来ずに困ってます。
そもそもサーバサイドスクリプトである以上、PHPではユーザの入力待ちをすることが出来ないのでしょうか?
もし実現できるのであれば、どのようなコードで実装すれば良いのか教えてください。よろしくお願いします。
※1つのPHP上でのトランザクション&排他制御の実装についてはテスト済みですので回答不要です。
WebアプリケーションサーバとしてのPHPは、WebサーバのRequest中のみ生存するので、通常はページの表示が完了した時点で終了します。
mysqlであれば、http://php.net/mysql_pconnectを利用することで、Requestが終了しても、接続を持続することが出来ます。
通常DBとの接続は1回のリクエスト処理の間のみに限定されるので、複数リクエストにまたがる場合は、DBMSに頼らない別のアプローチが必要となります。
例えばエンタープライズ アプリケーションアーキテクチャパターン (Object Oriented Selection)で紹介されている方法として、以下の2種類があります。
詳細は本を見ていただければと思いますが、前者はDBのレコードにバージョン番号をつけて、編集開始時と完了時に同じバージョンかどうかを確認するという方法です。誰かが間に割り込んで編集した場合、バージョンが異なるので判別できます。もっともこれは排他ではなく編集完了時に初めて編集処理がバッティングしたことがわかるというものですが。
後者は、排他対象となるものを自前で管理する方法だったかと思います(手元に本がないので断言できませんが)。編集対象レコードのID等を自前で覚えておいて、それを使って編集可否を判断させる方法です。
ただPC3台程度であれば、DB接続自体を保持しておいてもよいのかもしれません。PHPには詳しくないのですが、DB接続をセッションに入れて1クライアント1接続の形にして、その接続上でトランザクション制御を行う方法が取れるかもしれません。
ご回答ありがとうございます!
DBMSの機能を使わずに自前でトランザクションや排他のシステムを考慮する必要があるのですか。。orz 現在Accessでシステムを実装出来てるので、同じように実装したいのです。。自前で組むと不具合出そうですし(汗)
まさに最後の2行に書いてある『DB接続を維持してトランザクション制御を行う』ことをやりたいのですが、その具体的な実装コードが知りたいのです。
studioesさんの仰ってたmysql_pconnectで実現出来るのであれば、具体的なソースで教えて頂けませんでしょうか?(以前試した時は失敗しました)
対応はmysql_connectをmysql_pconnectに
書き換えるだけです。
php.ini(mysql.allow_persistent等の設定
は必要)
http://us2.php.net/manual/ja/features.persistent-connections.php
接続は維持されたままなので、エラーや
直前の状態の処理状態は維持されたままです。
pconnectでトランザクション処理が出来ても
期待した結果にはならないように思います。
例えばトランザクション処理でPC1が
1番のデータを処理しているとします。
トランザクション処理中であることは、
PC2,3はコミットされたデータしか
参照できないので1番のデータがロック
された事を知ることが出来ません。
知る為には、1番のデータが更新中である
事をテーブルに最初に書き込みコミットする
必要があります。
(トランザクション処理ではない)
実装するにしても以下のような処理に
なってしまうと思います。
テーブルtestとした場合カラムを追加
lockaddr char(32), index(lockaddr),
lockdate datetime,
を追加して
検索UniqueキーをidとしてPHP変数$id,$addr
(PCのIPアドレスで排他制御する)を得る
$addr = $_SERVER['REMOTE_ADDR'];
$id = 123;
$addr,$idを検索用に編集$sql_addr,$sql_id
する。
$sql_addr=mysql_real_escape_string($addr);
$sql_id = mysql_real_escape_string($id);
現在の1.~5は、
2.ロックを行う。
(放置防止の為600秒以上経過したものは
編集可能とする場合)
$sql = "update test set lockaddr='${sql_addr}',lockdate=now() where (id = ${sql_id}) and (lockaddr is null) or ((lockaddr is not null) and (now() > date_add(lockdate,interval 600 second))) ";
mysql_affected_rowsの件数が1の場合成功
0の場合だれか編集中
3.編集中のデータは、
セッションデータや、登録一時テーブル
などに保存
自分が編集中であるか確認するSQL
$sql = "select lockaddr from test where id=${sql_id} and lockaddr='${sql_addr}' ";
mysql_num_rowsの件数が1の場合まだ編集
可能、0の場合だれか編集中
4.-5.
最後の更新部分だけトランザクションにする。
begin
必要なカラムを更新
編集を終了
$sql = "update test set lockaddr=null where id = ${sql_id} and lockaddr='${sql_addr}'";
mysql_affected_rowsが1の場合更新成功
0の場合誰かに更新されている
commit or rollback
ご回答ありがとうございます。
・・・拝見させて頂いたのですが、上記はmysql_pconnectでトランザクション&排他制御を実装するサンプルコードではなく、自前で排他制御っぽぃ動作を行うサンプルですよね。。(通常のmysql_connectでも実装可能そうだし、データの整合性についても不安が残ります。。)
長文でご回答頂いたのに大変恐縮ですが、トランザクション処理と排他制御をDBMSの機能で実装出来ないのであれば、わざわざPHP+MySQLで実装する意味は無いと思ってます。(他の言語+DBの組み合わせで実装出来るので)
DBMSの機能を利用して『PHPをまたがるトランザクション&排他制御の実装』が可能なのであればその具体的なコードを教えて下さい。
実装不可能なのであれば、そうだと教えて下さい。よろしくお願いします。
>PHPをまたがるトランザクション&排他制御の実装
対応はmysql_connectをmysql_pconnectに
すれば接続は維持されますが。
ためしみればわかりますが、リロードや
複数画面などの条件で複数の接続が発生
するになり、同じ接続につながる保障も
なく動く場合もあるかもしれませんが
期待するトランザクション処理の動作保障は
無理です。
>わざわざPHP+MySQLで実装する意味は無い
>と思ってます
PHP/MYSQLに限らず通常は
通常はユーザーの入力などで時間がかかる
処理がある場合、
トランザクション+処理の排他制御
は別の実装が必要です。
トランザクションでアトミックな操作実現
する手段として、データの排他制御を
行う必要があります。データの排他制御は
同時に処理を行わない為に必要で
トラクザクション処理を短時間に完了
して開放する事が通常前提です。
データの排他制御であって処理の排他制御
を目的とはしていません。
http://ja.wikipedia.org/wiki/%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B...
>1.物件を検索する
>2.物件の修正ボタン押下
今回の場合、1.の処理でだれかが処理中の
物件もトランザクション処理中であっても
2.で選択可能状態になり選択したPC
は待ち状態状態になります。
防止するには、物件が更新中である
事をデータベースを更新しておく必要があります。
この処理が処理の排他処理にあたります。
この部分をトランザクションの利用すると、
操作上は同じデータを修正する事が出来てしまい
操作したPCは処理が完了するまで待ち状態
で停止する事になります。
早速のご回答ありがとうございます!
やはりページ表示が完了した時点で終了するのですね。。
mysql_pconnectは以前試したことがあるのですが、どうもうまく行かなかったんです。(多分記述方法が良くなかったのだと思いますが。。)
出来れば具体的なソースで教えて頂けると嬉しいです。
あと、mysql_pconnectは何を基に接続を判断してるのでしょうか?
PC3台程度のLAN環境で使うのですが、例えばPC-Aが更新中に、PC-BやPC-Cが検索や更新(同じデータだったら排他で弾いて、違うデータだったら別トランザクションで開始したい)する場合、同じPHPスクリプトを動作させても混乱しないのかな?と思いまして。