• ベストアンサー

DB切断のタイミング(perlでは切断されない?)

perlのDBIからMySQLに接続しています。 一連の処理の中で、disconnectをしても実際には暗黙的にプログラム終了時に切断されるので、厳密にはdisconnectは不要とのこと(この認識が間違っていたらご指摘ください)。 実際に試してみたら、切断した後でも同じデータベースハンドルが使用できました。 で、問題は、一連の処理の中でセッションはどのように扱われるのでしょう。切断されることなく同じセッションが使いまわされるのでしょうか? 具体的には、以下のようなことで悩んでいます。 接続→SELECTで必要データを取得→切断 という処理をするサブルーチンがあり、このサブルーチンをメインルーチンから複数回呼び出しています。つまりロジック的には接続と切断を何度も繰り返すような流れになっています。 これはこれで期待通りの動作をするのですが、何度も接続・切断を繰り返すより、メインルーチンで一度だけ接続しておいて、そのデータベースハンドルを引数と一緒にサブルーチンに渡す、そしてメインルーチンで最後に切断、という仕様に変更したほうが、効率が良いのでは、と考えました。 しかし、ロジック的には接続・切断を繰り返しているように見えても、実際にはそれぞれ一回ずつしか行われていないのなら、カプセル化という意味ではサブルーチンの中で接続・切断を書いた方が良さそうに思えます。 実際のところ、終了処理などのタイミングが良く解っていないのがいけないのですが、どなたか、どちらが良いのか、実際に切断がいつ行われるのか、ご存知でしたら、よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • zebedeer
  • ベストアンサー率66% (80/121)
回答No.3

>ロジック的には では、package hogeの下でconnectして、$dbhはhogeのpackage変数として持ってみては? package hoge; use DBI; $dbh = DBI->connect unless $dbh; sub new {}; sub DESTROY{#必要であれば $dbh->disconnect if $dbh; } この方法ならmod_perl環境でも使いまわせるので良いかもしれません。 (まぁ、mod_perl+DBIならApache::DBI使うか)

SV576
質問者

お礼

なるほど。おっしゃるとおりです。 サブルーチンかメインルーチンか、にばかり気を取られて、モジュール自体のスコープを忘れていました…。 これなら呼び出し側から隠蔽されるし、接続も保持されますね。 大変助かりました。 ありがとうございます。

その他の回答 (2)

  • zebedeer
  • ベストアンサー率66% (80/121)
回答No.2

>厳密にはdisconnectは不要 使い方によってはdisconnectが必要ですが、使い方によってはdisconnectは不要です。 (AutoCommitやfinish、commit等の使い方によって) >切断されることなく同じセッションが使いまわされるのでしょうか? この辺はDBDに依存すると思います。 >何度も接続・切断を繰り返すより、メインルーチンで一度だけ接続 基本的にこっちの方が効率が良いです。 (ただし、DBDによっては、悪いことはなくても変わらないかも) ちなみに私は開始時にDBI->connectして終了時に$dbh->disconnectしています。 ($dbhはグローバル変数に保存)

SV576
質問者

お礼

ご回答ありがとうございます。 やはり接続・切断はメインルーチンで管理したほうが良いでしょうか。 サブルーチンとは言っても外部のモジュールファイルに入れているので、なるべくならメインの方では「(DBを意識する必要なく)情報を取ってくるだけ」に見えたほうがいいと考えたのですが、やはり効率などの面では良くないのですね(実装によっては変わらないとしても)。 ロジック的にはどう思われますか?上記のようにサブルーチンをカプセル化することと、それをすることによる影響の、すりあわせと言いますか、判断材料としては、やはり呼び出す回数などでしょうか。

  • angband
  • ベストアンサー率51% (86/168)
回答No.1

DBIのマニュアルによると disconnectは接続を切断すると明記されていますので、 基本的には切断されると思うのですが、実装上すぐに切断しないのかもしれない ですね。 MySQLでdisconnectが不要と言われるのは、昔のテーブルタイプでは、 トランザクションをサポートしていないために、disconnect呼び出し時に 特に処理がないために、プログラム終了->(勝手に)切断 でも問題が ないということみたいです。(MySQLのマニュアルより) ただこの質問の内容については、マニュアルに記載されていることよりも さらに深い実装に関することなので、今現在DBIが使っているパフォーマンス上の トリック(DBIオブジェクトがすぐに接続を破棄しないように見える)に依存した プログラムを作らない方がよいのではないでしょうか。 回答になってないかと思いますが、検証という意味では、プログラムを disconnectの呼び出し前後で止めて、コマンド mysqladmin processlistで どのスレッドがどのDBに接続してるか調べることで、タイミングは 調べられるのではないでしょうか。

SV576
質問者

お礼

ご回答ありがとうございます。 確かに、おっしゃるように実装などに依存した作りは良くないかもしれませんね。 今回悩んでしまったのは、質問文にも書いたようにカプセル化の観点からなんですよね。 サブルーチンとは言っても外部のモジュールファイルに入れているので、その主旨から言えば、メインのスクリプトからはDBの接続などを意識することなく、もっと言えば、DBの存在すら知らなくても、ただ情報が取り出せる、ような作りにしたかったからです。 やはりロジック的に正道な方法で、メインルーチンで接続→サブルーチンに渡す…、最後にメインルーチンで切断、というのが良いでしょうか。 ただ、ご指摘いただいたことを逆に考えれば、効率などを気にしなければ、接続・切断を繰り返そうと、一向に問題はないわけですよね。 ロジック的に、あるいはスマートな方法は、どちらだと思われますか?