2011-12-28 4 views
2

У меня есть простой скрипт Perl, который прослушивает сетевой порт, принимает данные и записывает данные в базу данных с использованием DBD :: ODBC. Это выглядит примерно так:Обработка критических ошибок DBD :: Ошибки ODBC

#!/usr/bin/perl 
my $dbh = DBI->connect('dbi:ODBC:SqlProd',"yay","ooo",{AutoCommit => 0}) || die "Couldn't connect to db"; 
my $sth = $dbh->prepare("insert into table some stuff"); 

$sock = IO::Socket::INET->new(LocalPort => '1234', Proto => 'udp')||die("Socket: [email protected]"); 
do { 
    $sock->recv($buf, $MAXLEN); 

    /*parse some data here*/ 
    /*bind some parameters to $sth here*/ 

    my $rv = $sth->execute() || warn logit('warning', "Error inserting to db: $! $msg"); 
    $dbh->commit() || warn logit('err',"Error committing db transaction: $! $msg"); 

}while(1); 

Это, будучи немного сырым, работает достаточно хорошо. Однако, по неизвестным причинам, база данных идет вниз и сценарий аварий говорить вещи, как:

DBD::ODBC::st execute failed: [unixODBC][FreeTDS][SQL Server]Write to the server failed  (SQL-08S01) at /usr/local/bin/haproxy-syslog line 117. 
0 at /usr/local/bin/haproxy-syslog line 117. 
DBD::ODBC::db commit failed: [unixODBC][FreeTDS][SQL Server]Could not perform COMMIT or  ROLLBACK (SQL-HY000) at /usr/local/bin/haproxy-syslog line 118. 
Error committing db transaction: Connection reset by peer 
DBD::ODBC::db DESTROY failed: [unixODBC][FreeTDS][SQL Server]Could not perform COMMIT or ROLLBACK (SQL-HY000) during global destruction. 

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

ответ

1

Проблема вызвана тем, что несмотря на то, что функция execute() не работает, вы все равно вызываете commit(). Поскольку соединение отсутствует, вы не можете отправить БД на вызов фиксации. Кроме того, похоже, что у вас есть AutoCommit, так что БД пытается закрыть любые открытые транзакции при удалении соединения в вызове DESTROY.

Вы могли бы попробовать что-то вроде этого (простите мой ржавый Perl):

do { 
    $sock->recv($buf, $MAXLEN); 

    # parse some data here 
    # bind some parameters to $sth here 

    my $rv = $sth->execute() || warn logit('warning', "Error inserting to db: $! $msg"); 
    if ($msg ~= /connection reset/i) 
    { 
     warn logit('warning', "Connection disconnected."); 
     $sth->disconnect(); 
     break; # exit while 
    } 
    $dbh->commit() || warn logit('err',"Error committing db transaction: $! $msg"); 

}while(1); 
+0

Если бы я хотел, чтобы не выйти из цикла, а просто подождать некоторое время для DB, чтобы вернуться, прежде чем продолжить, я мог бы просто позвонить 'спать' немного? Кроме того, '' msg' автоматически заполняется командой 'execute'? – growse

+0

Если вы не хотите выйти, вам нужно будет создать новое соединение. Замените 'break' новым вызовом' DBI-> connect() '. Вам придется перестроить свой цикл для поддержки повторных попыток, чтобы вы не отбрасывали сетевые сообщения. – saarp

+0

На самом деле я не беспокоюсь о снижении сетевого трафика, хотя я ценю эту мысль. Я пойду и посмотрю, что я могу найти. – growse

Смежные вопросы