DBI: подключиться к другой базе данных, если первая база данных не существует

Я пытаюсь отсортировать наш устаревший код, который служит двум целям. Он использует DBI для созданиябазы данных, а затем использует DBI для подключенияк этой базе данных. К сожалению, для каждого из них использовался один и тот же код. Это означает, что если вы создаете базу данных sales, позже, при использовании повторного подключения, вы должны явно вызвать $dbh->do('use sales'). Это приводит ко всевозможным проблемам, например, к тому, что разработчики забывают это сделать, или дескриптор базы данных переподключается и забывает, в какой базе данных он находится.

То, что мы пытаемся сделать в качестве исправления первого прохода, заключается в том, чтобы метод DBI::connect()использовал HandleErrorдля повторного подключения к MySQL, если база данных не существуют, что позволяет нам создать базу данных. По разным устаревшим причинам (да, мы все сталкивались с этим) гораздо сложнее попытаться перехватить ошибку «Неизвестная база данных» вне метода connect().

Таким образом, мой первый подход к решению этой проблемы выглядит следующим образом:

use strict;                                                                                                                                               
use warnings;
use DBI;
use PadWalker 'peek_my';
my $dbh = DBI->connect(
    $dsn,
    $user,
    $pass,
    {   RaiseError  => 1,
        PrintError  => 0,
        HandleError => \&reconnect_if_unknown_database,
    },
);

sub reconnect_if_unknown_database {
    my ($msg, $drh, $dbh) = @_;
    return unless $msg =~ /Unknown database/;

    my ($dsn, $user, $pass, $attr) = @{peek_my(1)}{qw/$dsn $user $pass $attr/};

    unless ($dsn && $user && $pass && $attr) {
        return;    # don't do this if we can't get everything
    }

    # they're all scalar refs.
    $_ = $$_ foreach $dsn, $user, $pass, $attr;

    unless ($dsn =~ s/^[^;]+;/DBI:mysql:mysql;/) {
        return;    # can't parse dsn, so return
    }
    delete $attr->{HandleError};    # infinite loops tickle

    $_[2] = DBI->connect($dsn, $user, $pass, $attr);
}

Это работает и в настоящее время прозрачно для конечного пользователя, но это также похоже на дымящуюся кучу нулей и единиц. Есть ли лучший способ повторного подключения к другойбазе данных при сбое подключения?

6
задан Ovid 4 May 2012 в 12:53
поделиться