在Perl中跟踪不确定的MySQL错误



我有一个在托管共享服务器上运行的单线程Perl脚本,它主要执行以下代码:

my $O_dbh = DBI->connect("dbi:mysql:dbname=dbname", "abc", "xxx", {RaiseError => 1});
$O_dbh->begin_work();
my $O_sth1 = $O_dbh->prepare('SELECT COUNT(*) FROM mytable WHERE any = 5');
$O_sth1->execute();
my @result1 = $O_sth1->fetchrow_array();
my $oldValue = $result1[0];
$O_sth1->finish();
my $O_sth2 = $O_dbh->prepare('INSERT INTO mytable (any) VALUES (5)');
$O_sth2->execute();
$O_sth1->execute();
my @result2 = $O_sth1->fetchrow_array();
my $newValue = $result2[0];
if ($oldValue + 1 == $newValue) {
  $O_dbh->commit();
} 
else {
  $O_dbh->rollback();
  die "why?! new = $newValue, old = $oldValue";
}

有时(<1%),代码会遇到回滚情况并失败。在我的本地系统上,我无法重现此错误。数据库为MySQL 5。

CREATE TABLE `mytable` (
  `id` int(11) NOT NULL auto_increment,
  `any` int(11) NOT NULL default '1',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

如何追踪此错误?如有任何帮助,我们将不胜感激。

假设您的数据库使用默认设置运行,我更惊讶的是,您的SELECTever返回两个不同的值。

文件上说这个

如果事务隔离级别为REPEATABLE READ(默认级别),则同一事务中的所有一致读取都将读取该事务中第一次此类读取所建立的快照。通过提交当前事务,然后发出新的查询,可以为查询获取更新鲜的快照。

因此,如果默认的REPEATABLE READ隔离级别有效,我希望所有查询都会返回与第一次查询时数据库状态一致的数据。

然而,这听起来确实有助于

使用READ COMMITTED隔离级别,事务中的每个一致读取都会设置并读取自己的新快照。

我认为你应该试试

$O_dbh->do('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED');

连接后立即,看看这是否能为您解决问题。

但是,您应该确保在此事务之后disconnect数据库句柄,或者将其返回到以前的隔离级别。否则,您将开始得到不一致的结果。

最新更新