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

Check database connection before open a new one

我的应用程序结构如下:

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

在 Database::Db 中,我有一个创建到 SQL SERVER 的连接的子例程。该子例程被导出并在 Main.pm
中使用 示例:
Database::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' );
});

谢谢

这是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 is like "connect", except that the database handle returned is also stored in a hash associated with the given parameters. If another call is made to connect_cached with the same parameter values, then the corresponding cached $dbh will be returned if it is still valid. The cached database handle is replaced with a new connection if it has been disconnected or if the ping method fails.

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

从 DBIx::Connector 对象使用 dbh 方法然后将其用作普通 DBI 句柄是安全的,但是您会错过 DBIx::Connector 的大部分好处如果您不保留 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(...);