我有一个简单的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: $@");
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.
如果我希望脚本能够恢复这种类型的故障,可以等待一段时间,看看数据库是否再次唤醒,或者丢弃收到的数据并从套接字中提取更多数据,什么是最好的方式呢?上述错误是否意味着$ dbh最终成为垃圾并且需要重新初始化?
答案 0 :(得分:1)
问题是由于即使execute()失败,您仍然在调用commit()。由于没有连接,因此无法向DB发送提交调用。此外,您似乎已启用AutoCommit,以便DB在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);