2011-12-28 54 views
2

我有一个简单的Perl脚本,它监听网络端口,接受数据并使用DBD :: ODBC将数据写入数据库。它看起来有点像这样:正常处理Perl关键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调用中的连接时,DB尝试关闭所有打开的事务。

你可以尝试这样的事情(原谅我糟糕的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 2011-12-29 11:04:52

+0

如果你不想退出,你将不得不建立一个新的连接。将'break'替换为对'DBI-> connect()'的新调用。您将不得不重构您的循环以支持重试,以便您不会丢失网络消息。 – saarp 2011-12-29 16:41:38

+0

我其实并没有对减少网络流量感兴趣,尽管我很欣赏这个想法。我会去看看我能找到什么。 – growse 2011-12-29 17:22:20