2010-09-10 59 views
2

我正在使用这种方法。如果sql中有错误,则回滚仅发生在asset_group的第一个id上。其余的ID被忽略。我是否正确地做?perl dbi回滚不起作用

my $sql = "sql batch that update and insert depending on the condition"; 
$dbh->{RaiseError} = 1; 
$dbh->{PrintError} = 0; 
$dbh->{AutoCommit} = 0; 

my $sth = $dbh->prepare($sql); 
my @error =(); 
my $num = 0; 
foreach my $id (@asset_group) { 
next if ($id eq ''); 
eval { 
    $sth->bind_param(1, $id); 
    $sth->bind_param(2, $vars{'other_id'}); 
    $sth->execute(); 

}; 
if ([email protected]) { 
    $dbh->rollback(); 
    push @error, [email protected] 
} else { 
    $dbh->commit(); 
} 
} 
+1

你是什么意思“其余的ID被忽略?” – cam 2010-09-10 16:47:22

+0

即使您关闭了AutoCommit,您可能也希望使用'BEGIN'和'END/COMMIT/ROLLBACK'明确设置事务。你正在使用哪些DBMS? – vol7ron 2010-09-10 17:27:45

+0

小心,提交也会失败。 – bohica 2010-09-13 08:40:46

回答

7

根据数据库的不同,您可能需要在开始更改之前发出begin work。我似乎记得Informix需要一个。

另外,它看起来像是在每次执行后发出提交或回滚。一旦提交,就不能回滚。通常有人说类似

$dbh->begin_work; 
eval { 
    for my $id (@asset_group) { 
     next if ($id eq ''); 
     $sth->execute($id, $vars{other_id}); 
    } 
    1; #if it doesn't die then this will force it to return true 
} or do { 
    my $error = DBI->errstr; 
    $dbh->rollback(); 
    die "could not insert rows: $error\n" 
}; 
$dbh->commit(); 

注意我怎么不使用[email protected][email protected]untrustworthy

+0

你不需要调用'begin_work'。它的存在主要是为了允许您为特定的一组操作使用事务,即使您打开了AutoCommit。在AutoCommit关闭的情况下(就像这里),如果数据库不支持事务处理,它所做的全部事情都会消失。但你的答案的其余部分是很好的建议。 – cjm 2010-09-10 17:38:02

+0

谢谢大家。有效。 – alp 2010-09-10 18:06:26

+1

@alp,那么您应该通过点击其分数附近的复选标记来将答案标记为已接受。 – cjm 2010-09-10 18:12:31