2010 Perl Advent Calendar などでも説明していた Scope::Container でDBの接続管理を行うモジュールを書いた。
CPAN: http://search.cpan.org/dist/Scope-Container-DBI/ github: https://github.com/kazeburo/Scope-Container-DBI
機能的には、Scope::Container に接続情報をキャッシュして、同じDSN・ユーザ名で接続の場合、キャッシュからdbhを返します。Scope::Containerなので任意のスコープで接続の維持と切断ができます。
Scope::Container::DBIには、connectメソッドがあるだけ。DBIと同じくdsn、ユーザ名、パスワード、オプションを渡す。
use Scope::Container::DBI;
use Scope::Container;
sub work {
my $contaier = start_scope_container();
for (1..n) {
# 最初の1回だけ接続。あとはキャッシュされる
my $dbh = Scope::Container::DBI->connect(
'dbi:mysql:mydb;host=myhost', 'myuser', 'mypasswd',
{ RaiseError => 1, mysql_connect_timeout => 4, mysql_enable_utf8 => 1 }
);
}
#$contaierが破棄されるまで接続はキャッシュ
}
Plack::Middleware::ScopeContaierと組み合わせると、1リクエスト中だけ永続接続が簡単に実現できます。
あと、複数のdsnをarrayrefで渡すと、その中からランダムで選び出して接続をすることもできます。slaveを並べる場合などに使えます。
use Scope::Container::DBI;
use Scope::Container;
my $dbh = Scope::Container::DBI->connect(
['dbi:mysql:mydb;host=myslave01', 'myuser', 'mypasswd', {..}],
['dbi:mysql:mydb;host=myslave02', 'myuser', 'mypasswd', {..}],
['dbi:mysql:mydb;host=myslave03', 'myuser', 'mypasswd', {..}],
);
これも接続をキャッシュして1回だけ接続が行われます。
あと、Scope::Container::DBIでキャッシュのdbhを再利用する場合にはDBIx::Connectorのように、プロセスID/スレッドIDを確認しているので、fork safeです。
MySQLの文字コードの設定など接続が完了した時点でなんらかのアクションをしたいことがあると思います。Scope::Container::DBIにはその機能はありませんが、DBI標準のCallbackが使えます。
my $dbh = Scope::Container::DBI->connect($dsn, $username, $password, {
RaiseError => 1,
Callbacks => {
connected => sub {
shift->do(q{SET NAMES utf8});
},
},
});
ちょっと長くなるけど使えるはず
おためしくださいませませ