【PostgreSQL】PHPとPostgreSQLの組み合わせで、例えば以下のようなソースがあるとします。


複数のユーザーが単一行を書き換える場合で、
間にSELECTで得たデータを必要とする処理があるので、あるユーザーが$query2のUPDATEを終了するまで$query1のSELECTをさせたくありません。

このような場合のトランザクションはどのようにしたら良いのでしょうか?
どうも隔離レベルの問題なのか何なのか、SELECTの前にBEGIN、UPDATE後にCOMMITさせても上手くいきません。
このような処理の場合の適切なトランザクションを下記ソースを書き換える形で教えてください。

$sql1 = "SELECT data1 FROM table1 WHERE deta2 = '123';";
$query1 = pg_query($sql1);

$array = pg_fetch_array($query);

// PHP側での処理を挟む
$buff = $array[data1] . $_POST[comment]

$sql2 = "UPDATE table1 SET data1 = '$rep' WHERE deta2 = '123';";
$query2 = pg_query($sql2);

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2007/04/20 09:11:40
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答3件)

id:studioes No.1

回答回数523ベストアンサー獲得回数61

ポイント20pt

pg_query("BEGIN");

pg_query("LOCK TABLE table1 ACCESS EXCLUSIVE MODE");

$sql1 = "SELECT data1 FROM table1 WHERE deta2 = '123';";

$query1 = pg_query($sql1);

$array = pg_fetch_array($query);

// PHP側での処理を挟む

$buff = $array[data1] . $_POST[comment]

$sql2 = "UPDATE table1 SET data1 = '$rep' WHERE deta2 = '123';";

$query2 = pg_query($sql2);

pg_query("COMMIT");

これでどうでしょ

id:tenshiks

有難う御座います。

確かに動作は問題ないかもしれませんが、テーブルごとロックされちゃいますよね…

2007/04/20 09:09:15
id:wnagata No.2

回答回数170ベストアンサー獲得回数18

ポイント50pt

以下のように、FOR UPDATEをselect文に指定するのが一番簡単でしょう。

この場合、ユーザAが$sql1を実行すると、ユーザBは$sql1

を実行しても、ユーザAがコミットまたはロールバックを行うまで、ユーザBは待たされ、ユーザBにはユーザAが更新したあとの結果が返されます。

$sql1 = "SELECT data1 FROM table1 WHERE deta2 = '123' for update;";

http://www.postgresql.jp/document/pg803doc/html/sql-select.html#...

selectのあと、必ずしもupdateが行われない場合は、楽観的ロックという方法がとられます。table_1にupdate_timeというtimestamp型のフィールドを用意し、update時にはupdate_timeをcurrent_timestampに更新し、where条件にselectしておいたupdate_timeを追加しておくという方法です。そして、updateされた行数が0の場合は、別のユーザに更新されているということなので、selectからやり直します。

id:tenshiks

有難う御座います。

よく理解しました。

丁寧な説明有難う御座いました。

2007/04/20 09:09:45
id:kurukuru-neko No.3

回答回数1844ベストアンサー獲得回数155

ポイント30pt

> select ....

select .... for update

に変更する。


 http://osb.sra.co.jp/PostgreSQL/Manual/PostgreSQL-7.1-ja/sql-sel... 

id:tenshiks

有難う御座います。

for update で大丈夫そうですね。

2007/04/20 09:10:18
  • id:kurukuru-neko

    厳密に処理をしてかつテーブル
    ロックをしたくない場合はロック用の
    テーブルで特定条件でロックを
    行う等の対策が簡単です。

    begin
    update locktable set dmy=now(),req=req+1 where lockid=xxx

    select ... for update

    commit / rollback


    http://www.postgresql.jp/document/pg824doc/html/transaction-iso.html

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません