[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さんはなぜテーブルのロックが必要になったのでしょうか。