[PHP-users 11633] Re: PHPでPostgreSQL のトランザクションを実行するには?

Mashiki php-users@php.gr.jp
Thu, 21 Nov 2002 02:12:27 +0900


 Mashikiです。

>有難うございました。確かにこれで30秒間ロックを掛ける事が出来ました。
>ただ、一つしっくりこないのがLOCK TABLEを実行するとCOMMIT or ROLLBACK が来る
>までLOCKしたまま
>になるかと思っていたのですがphpから行う場合ロックする時間を指定する必要があ
>るのでしょうか?
>それともINSERT、UPDATEが終わると自動的にロックが解除されるのでしょうか?

phpよりpg_connect()で接続した場合、insert、update後、phpのプログラムが
終了する際に、postgresとの接続が切れますが、その時、トランザクションは
ロールバックされると考えてください。

 :
> 他のツールとして
>「CSE」というSQL PLUSのようなツールを別のWindows端末から利用してトランザク
>ションを開始したところ
>正しく実行されましたのでPostgreSQLの側でなくPHPの方が悪いのではないかと

こちらの場合は、postgresとの接続を切っていなかったから、jsさんの期待する
結果となったわけです。

# sql*plusで本番のDBに更新をかけている最中に電話がかかってきて、
# 半日席をはずしたら、webサービスが半日止まったという、恐ろしい
# 実例を知っています。気をつけてくださいね :-)

>私のイメージだとCOMMITをプログラムから外すとテーブルをずっと読み込む事が出来
>ない状況が続くのだろう
>と思っていたのです。(もちろんこれはトラブルの原因になることは間違いないので
>自動ロック解除のがありがたいです)

>PHPからトランザクションを行う場合はテーブルロックのようが無ければ、自動的に
>解除してくれると解釈してもよいのでしょうか?

とりあえず、接続を切ったのでロールバックされたということでいいですよね。


トランザクションの必要性は
http://www.postgresql.jp/document/pg721doc/tutorial/tutorial-
transactions.html
を読んでみてください。(これ英文の和訳で読みにくいのですが誰かもっといい
例を知っている方は教えて!!)

たとえば、Aさんのお金を500円、Bさんに振り込むとした場合、

update 所持金表 set 所持金 = 所持金-500 where 人 = 'A';
update 所持金表 set 所持金 = 所持金+500 where 人 = 'B';

のような処理になりますが、Bさんの処理に失敗した場合、所持金の
合計が減ってしまうようなことになります。Bさんの処理に失敗した場合、
Aさんの処理もなかったことにしたい、というときに2つのSQLを
BEGIN...COMMITで囲うということです。

>明示的なロックが必要なケースはあまりないと思うのですがはっきりさせたいです。

私もそう思います。

上記の例で言えば、上のプログラムが、AさんBさんの順に処理し、
別のプログラムが同時にBさんAさんの順で処理した場合、デッド
ロックが発生し、どちらかのプログラムがabortされます。

 すべてのプログラムが例えばアルファベット順に処理すると
いうルールを守ってお行儀よく書かれていればいいのですが、
アプリケーションが複雑になってくるとこれが難しくなった
りします。その場合、テーブルロックでこの問題を避ける事が
できます。
 複数のテーブルにロックをかける必要がある場合、さらに
テーブルの更新順序を決めておく必要があります。

また、テーブル中のあるフィールドについて、他のレコードと
重複しない、最小のプラスの整数を見つけinsertするために、
テーブルロックをかける場合もある(人もいる)ようです。

# 個人的にはテーブルロックをかける必要があるようなテーブル
# の設計は嫌いなので、Lock table文は使ったことがないです。
# 使ったことを忘れているだけかも知れませんが...

jsさんはなぜテーブルのロックが必要になったのでしょうか。