複数のユーザーが単一行を書き換える場合で、
間に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);
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");
これでどうでしょ
以下のように、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からやり直します。
有難う御座います。
よく理解しました。
丁寧な説明有難う御座いました。
> select ....
select .... for update
に変更する。
http://osb.sra.co.jp/PostgreSQL/Manual/PostgreSQL-7.1-ja/sql-sel...
有難う御座います。
for update で大丈夫そうですね。
有難う御座います。
確かに動作は問題ないかもしれませんが、テーブルごとロックされちゃいますよね…