2012-05-04 14 views
6

İki amaca hizmet eden bazı eski kodlarımızı sıralamaya çalışıyorum. Bu veritabanına oluşturmak için DBI kullanır ve bir veritabanı oluşturmak ve daha sonra bu veritabanına bağlanmak DBI kullanır. Ne yazık ki, her biri için aynı kodu kullandı. Bu, sales veritabanını oluşturursanız, daha sonra yeniden bağlandığınızda, $dbh->do('use sales')'u açıkça aramanız gerektiği anlamına gelir. Bunu yapmak için geliştiricileri veya veritabanını yeniden bağlamayı ve hangi veritabanını unutmadığını her türlü soruna yol açar.DBI: İlk veritabanı yoksa, farklı bir veritabanına bağlanın

İlk geçiş düzeltmesi olarak yapmaya çalıştığımız şey, DBI::connect() yöntemine sahip olmaktır Veritabanı yoksa MySQL'e yeniden bağlanmak için HandleError kullanın, böylece veritabanını oluşturmamıza izin verin. Çeşitli eski nedenlerden dolayı (evet, hepimiz oradaydık), connect() yönteminin dışındaki "Bilinmeyen veritabanı" hatasını yakalamayı denemek çok daha zordur. işleri

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); 
} 

ve son kullanıcıya şu anda belli ediyorsun, ama aynı zamanda birler ve sıfırlar buharı tüten yığını gibi hissediyor şu şekildedir:

Böylece, bu çözümü benim ilk geçiş olduğunu. Bağlantı başarısızlığında farklı veritabanına yeniden bağlanmak için daha iyi bir yolu var mı? Bu işe olsaydı

+0

Tam bir test durumu büyük bir yardım olacaktır. "Her biri için aynı kodu kullandı" açık bir açıklama olmadan nasıl yardımcı olabileceğinden emin olmak zor. –

+0

Tim: Sanırım daha iyi bir açıklama "DBI'nin sadece DSN'yi değiştirerek başarısızlığa yeniden bağlanmasını sağlayabilir miyim?" Bunu yapmanın daha iyi bir yolu var mı bilmiyorum. – Ovid

cevap

7

Emin değilim ama PadWalker kullanarak tercih olabilir:

use strict;use warnings; 
use DBI; 

my %attr = (RaiseError => 1, PrintError => 0); 

my $dbh = DBI->connect(
    $dsn, 
    $user, 
    $pass, 
    { 
     %attr, 
     HandleError => sub { 
      reconnect_if_unknown_database(
       $dsn, $user, $pass, \%attr, @_ 
      ) 
     }, 
    }, 
); 

sub reconnect_if_unknown_database { 
    my ($dsn, $user, $pass, $attr, $msg, $drh, $dbh) = @_; 

    return unless $msg =~ /Unknown database/; 

    return unless $dsn =~ s/^[^;]+;/DBI:mysql:mysql;/; 

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

Vay. Ben bunu düşünmemek için bir aptalım :) – Ovid

+1

Ne dediklerini biliyorsun * sadece bir başka indirgeme seviyesi * ;-) –

+1

Muhtemelen yok, çünkü listenin sonunda '@ 'yazmalısınız. boyutunun gerçek kontrolü. – ikegami

İlgili konular