在打开新数据库之前检查数据库连接

时间:2018-10-22 14:34:01

标签: perl dbi mojolicious

我有一个结构如此复杂的应用程序:

 /root_dir/lib/Mojo_App/Controller/Main.pm  
 /root_dir/lib/Mojo_App/Database/Db.pm  
 /root_dir/ ...

在Database :: Db中,我有一个子例程,可创建与SQL SERVER的连接。该子例程在Main.pm中导出并使用
示例:
数据库:: DB

my $config = {
db1 => {
    host => 'dbi:Driver:server=ip01;database=db01',
    user => 'user01',
    pass => 'pass01'
},
db2 => {
    host => 'dbi:Driver:server=ip02;database=db02',
    user => 'user02',
    pass => 'pass02'
},
db3 => {
    host => 'dbi:Driver:server=ip03;database=db03',
    user => 'user03',
    pass => 'pass03'
}
};


sub connect_db {
use DBI;
my $self = shift;

return 0 unless $self;

my $dbh;

if (exists($config->{$self})) { 
    return $dbh = DBI->connect($config->{$self}->{host}, $config->{$self}->{user}, $config->{$self}->{pass}) || die( $DBI::errstr . "\n" ) ;
} else {
    return "Connection not in config. \n" ;
}
return $dbh; 

}

在Main.pm中,我这样连接:

my $dbh = connect_db('db1');

现在可以说我需要在索引页面上连接到数据库,因此在Main.pm中将有一个子例程索引,如下所示:

sub index {
    my $self = shift;
    my $dbh = connect_db('db1');
    ...
    $self->render();
}

现在,我不希望每次用户访问索引页面时都要建立新的连接,我想检查连接是否处于活动状态,以及是否不创建连接。
我已经阅读了有关ping方法的信息,但是我不知道如何在这里实现它。 我还阅读了有关DBIx的信息,并尝试了以下实现:

sub connect_db {
use DBIx::Connector;

my $self = shift;

return 0 unless $self;

my $dbh;

if (exists($config->{$self})) { 
    my $conn = DBIx::Connector->new($config->{$self}->{host}, $config->{$self}->{user}, $config->{$self}->{pass}, {
        RaiseError => 1,
        AutoCommit => 1,
    });
    return $dbh = $conn->dbh; ;
} else {
    return "Connection not in config. \n" ;
}
return $dbh; 
}   

此实现能否实现我想要的?当数据库连接处于活动状态时将被使用且未重新创建。如果是,那么像Dbi一样使用DBIx是否安全?我在这里指的是:

my $dbh  = $conn->dbh;
$dbh->do('INSERT INTO foo (name) VALUES (?)', undef, 'Fred' );
and not 
$conn->run(fixup => sub {
$_->do('INSERT INTO foo (name) VALUES (?)', undef, 'Fred' );
});

谢谢

2 个答案:

答案 0 :(得分:1)

使用DBIx :: Connector对象中的dbh方法,然后将其用作常规DBI句柄是安全的,但是如果您不这样做,则可能会错过DBIx :: Connector的大多数优点。 t保留DBIx :: Connector对象。创建一个新的DBIx :: Connector对象将意味着需要一个新的连接,因为该对象是连接的缓存位置。此外,每当您调用->dbh->run时,DBIx :: Connector都会检查该连接是否处于活动状态以及您是否未进行分叉,并在需要时建立新连接。因此,最好存储并传递DBIx :: Connector对象,然后让任何单独的代码段检索dbh或调用run。在Mojolicious应用程序中,通常将类似的内容存储在应用程序helper中(但当然,您可以将其放在方便的地方)。

# in application startup
my %dbs;
$app->helper(db => sub {
  my ($c, $name) = @_;
  return $dbs{$name} //= DBIx::Connector->new(...);
});

# elsewhere
my $dbh = $c->db('db1')->dbh;
# or
$c->db('db1')->run(...);

答案 1 :(得分:0)

DBI::connect_cached应该解决的问题:

$dbh = DBI->connect_cached($data_source, $username, $password)
      or die $DBI::errstr;
$dbh = DBI->connect_cached($data_source, $username, $password, \%attr)
      or die $DBI::errstr;
     

connect_cached类似于“ connect”,除了返回的数据库句柄也存储在与给定参数关联的哈希中。如果使用相同的参数值再次调用connect_cached,则如果仍然有效,则将返回相应的缓存$dbh。如果已断开连接或ping方法失败,则将缓存的数据库句柄替换为新的连接。

有关重要免责声明,请参阅文档。