我有一个简单的算法如下,为了清楚起见省略了不相关的事情:
while( my $data = get_data() ) {
process($data);
}
sub get_data() {
return $dbh->execute("SELECT * FROM TABLE WHERE status = 'submitted'");
}
sub process {
my $data = shift;
foreach my $row (@$data) {
handle($row);
}
}
sub handle {
my $row = shift;
# process logic here
$dbh->execute("UPDATE TABLE SET status='done'" WHERE id = $row->id");
}
现在问题是存在导致无限循环的错误。如果在处理和核心处理逻辑期间出现故障并且代码无法更新到状态,则在下一个循环中它将反复重试记录。
添加新状态我认为只是在其他地方移动相同的问题所以我认为我的逻辑存在某种缺陷
有没有办法让一个进程“理解”它被卡在一个循环中并且没有进展?或者根据@amit重新措辞:有没有办法避免无限循环?
我只想出以下几点:
1)当我执行get_data()
时,我将行添加到内存数组中,因此在下一个循环中我将执行SELECT * FROM TABLE WHERE status = 'submitted' WHERE id NOT IN (@array)
这可以工作但是对于大量记录,例如将它们放入IN中似乎是不切实际的
2)尝试查看更新的记录数。如果sizeof($ data)!=更新记录的数量,则可能意味着卡在流程中。
这些方法对我来说都不好看。有人可以帮我解决这个问题吗?
答案 0 :(得分:1)
如果您不想使用内存阵列(我不会责怪您),您是否可以修改现有表格或创建另一个表格?如果是这样,您可以将成功更新的记录移动到新表中,即使它只有2列,然后:
sub get_data() {
return $dbh->execute("SELECT * FROM TABLE WHERE ID NOT IN (SELECT ID FROM NEW_TABLE)");
}
处理这么多记录以维护内存中的散列/数组很困难,尤其是当你的应用程序由于某种原因崩溃时。至少通过这种方式你正在取得进步。
我没有在编程逻辑中看到一种不同的方式来处理这个问题。
答案 1 :(得分:0)
由于此行
,您显示的代码将无法编译$dbh->execute("UPDATE TABLE SET status='done'" WHERE id = $row->id");
有太多的双引号字符来平衡。
我认为你自己会混淆这么多子程序来执行一项简单的任务。我相信这个简短的程序会做同样的事情,我认为它更具可读性。
请注意,最佳做法是prepare
每个语句,并在准备好的SQL字符串中使用占位符,以便后续的execute
可以传递实际数据。
我无法测试此代码,因为设置示例数据库需要一段时间;但我已经检查过它编译了。
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect('dsn', 'username', 'password');
my $select = $dbh->prepare(q{SELECT * FROM TABLE WHERE status = 'submitted'});
my $set_done = $dbh->prepare(q{UPDATE TABLE SET status = 'done' WHERE id = ?});
$select->execute;
while (my $row = $select->fetchrow_hashref) {
$set_done->execute($row->{id});
}
一旦你开始运行,我就会遇到一些问题
如果TABLE
只要id
,那么您就不应该使用SELECT *
您只需撰写UPDATE TABLE SET status = 'done' WHERE status = 'submitted'
但也许你的真实情况更复杂?请告诉我们,以便我们能够更好地为您提供帮助。