Mojolicious — соединение с базой данных

После некоторых экспериментов я пришёл к такой схеме соединения с базой данных: соединение в хуке after_static_dispatch. Преимущества — в начале сессии один раз проверяется доступность базы и переоткрывается соединение, нет лишних врапперов для DBI хэндла.

Альтернативные варианты содержат недостатки:

— ping() перед каждым запросом и пересоединение с базой при отсутствии связи. Это приводит во всех случаях к лишним расходам на ping() — а они довольно значительные, на простых запросах 10-20%; что гораздо хуже, если это случается в середине транзакции, пересоединение с базой для выполняющегося приложения происходит незаметно, и целостность транзакции нарушается;

— соединение один раз при старте потомка после fork() — при разрыве соединения с базой оно не восстанавливается и HTTP запрос прерывается, и хорошо если при этом процесс Mojolicious (hypnotoad) тоже завершается — а он ведь не завешается, а только выдаёт ошибку клиенту и ждёт следующего запроса;

— соединение в начале обработки контроллера — это просто накладно по ресурсам СУБД.

— использование врапперов кроме накладных расходов содержит все вышеперечисленные недостатки, причём несмотря на то, что в документации они описаны, их не всегда принимают во внимание. Ну и исходные тексты тоже не читают.

Рекомендацию по соединению с базой в https://groups.google.com/d/msg/mojolicious/shf0kETALH0/f4btGkzqhgsJ я считаю в корне неправильной…

[cc lang=’perl’ ]
package MojoApp;
use Mojo::Base ‘Mojolicious’;
use DBI;

has ‘dbh’;

sub connectDB {
my $c = shift;
my $app = ( UNIVERSAL::isa( $c, ‘Mojolicious::Controller’ ) ) ? $c->app : $c;
unless ( UNIVERSAL::isa( $app->dbh, «DBI::db» ) && $app->dbh->ping() ) {
my $cnf = $config->{db};
$app->dbh(DBI->connect(«dbi:Pg:dbname=test;host=localhost;port=5432», ‘user’, ‘password’, ));
} ## end unless ( UNIVERSAL::isa( $app…
else {
$app->dbh->rollback();
}
} ## end sub connectDB

# This method will run once at server start
sub startup {
my $self = shift;

$self->hook(
after_static_dispatch => sub {
my ($c) = @_;
my $type = $c->res->headers->content_type;
connectDB($c) unless $type;
}
);
} ## end sub startup

1;
[/cc]

Leave a Reply