- - PR -
PostgreSQLのJDBCのcommitのタイミングについて
投稿者 | 投稿内容 |
---|---|
|
投稿日時: 2007-09-18 14:57
どうも、こんにちは。
今、PostgreSQLをJDBC経由で操作するプログラムを書いています。 変更をコミットする際に、JDBCのcommit()を呼んでいるのですが、どうも、commit()メソッドは、PostgreSQLのDBサーバー側のcommitの処理が終わる前にクライアントに処理が返ってくるようなのです。 なぜ、そのようなことが気になるかといいますと、DBレベルで、行ロックをして排他処理を行うのではなく、Javaのクライアント側で排他処理をさせてDB側の負荷をなるべく減らすようなことを考えていたからです。 (もし、commitの処理が終わるまでJDBCのcommit()メソッドがブロックしてくれないと、クライアント側での排他処理は無理) その辺の動作についてPostgreSQLでは設定できるのでしょうか?もしくは同じような経験をした方がいらっしゃったら教えていただけると幸いです。 なにとぞ、よろしくお願いいたします。 _________________ Alinous-Core SQL-HTML Language commiter Tomohiro Iizuka http://jp.alinous.org https://sourceforge.jp/projects/alinous-core/ |
|
投稿日時: 2007-09-18 17:33
率直な意見としては「Java側でやるべきではない」
というのも、ACID属性が満たされているDBは排他処理が必ず行われているからです。 DB側の排他をOFFにすることなんてできましたっけ? 結局JavaとDBとで2重に排他するだけではないでしょうか。 仮にDBに排他をOFFにする機能があったところで、独自に排他してACID属性を満たそうなどとすると、非常に難易度の高いプログラムを独自に開発することになるのではないでしょうか。 私は手を出したいとは思わないですね。あまりに危ういので。 |
|
投稿日時: 2007-09-18 19:43
nagiseさん、こんにちは。
この投稿をしてから、わたしもいろいろと考えていたのですが、まさにそのとおりですね。 行ロックを使っても十分なパフォーマンスが出ますので、DBサイドに排他処理をさせる方向でいこうと思います。 本当に、答えていただいてありがとうございます。 |
|
投稿日時: 2007-09-18 20:16
遅レスですが・・
プログラムで排他制御しても、物理的にDBにアクセスできる以上、 DBの管理ツールなどで更新してしまうと、一貫性がなくなってしまいます。 排他制御の仕組みによっては、排他しっぱなしとかになるケースも。 気をつけてメンテナンス使用と思っても、対象の行が操作してよいのか判断できません。 DBのロック機構であれば、物理的に操作できないので問題ないわけですが。 素直にDBに任せるのがよいかと思います。 |
|
投稿日時: 2007-09-18 20:24
かつのりさん
御返信ありがとうございます。 そうですよね、つい、Javaサイドでやろうなんて、変な色気をだしてしまいました。 色気をだしてしまった場所は、セッションDBの部分なんですが、本当にパフォーマンスで困ったときで、DBの用途が限られていたら、データベースっぽい部分を自分で書くという方法もありますもんね。むしろその方がよいと思いました。 しかも、埋め込む先が自分の作ったオープンソースのサーバーコンポーネントなのでソースのカスタマイズに自由が効きますから、ますます、自分でセッションDB特化のDBをいざとなったら自分でC++で書く方向が良いと思いました。 |
|
投稿日時: 2007-09-18 21:22
本題から外れますが、コミットしたつもりが実はコミットできていない可能性があるというのは、PostgreSQL的にまずいですよね。
それがPostgreSQLサーバ側の問題なのか、JDBCドライバ側の問題なのかは分かりませんが。 もしお手数でなければ、その事象をどのように確認したのか教えてもらえませんか? |
|
投稿日時: 2007-09-18 21:36
カーニーさんこんにちは。
実は、その問題もあるんですよね。commitが返ってきた時点でDBエンジンの方がまだ処理中ということは、ある意味、エラーが起きてもDBのクライアントが気づかないのでまずいです。 どのようなときに、その問題が発生したかというと、 BEGIN; DELETE FROM TABLE1 WHERE id = 'aaaa'; INSERT INTO TABLE1(id, data) VALUES('aaaa', 'data'); COMMIT; (idカラムは主キー) というような処理を、クライアントサイドでは同時に実行しないよう排他処理を行う処理を書きました。 (BEGINからCOMMITまでの処理をJavaでいうsynchronized修飾子のついたメソッドで実行しました) この処理を高負荷の元で実行すると「duplicate key」のエラーが発生したので、これは、DBのサーバーサイドでcommit処理が終わっていないのにJDBCのcommit()メソッドが返ってきてしまっているなと判断しました。 隔離レベルは、JDBCのコードでSERIALIZABLEにして実行しました。 ちなみに、同じ処理をApache DerbyとMySQLで実行したときにはこのようなエラーは起きませんでした。 |
|
投稿日時: 2007-09-18 21:43
自己レスですみません。
隔離レベルは、JDBCのコードでSERIALIZABLEにして実行しました。 と書きましたが、これは、READ COMMITEDで同じ現象が起きたとしてもcommitが保障されていないということになるんですよね。 |