Perl 叉子+;DBI和语句句柄 处境

Perl 叉子+;DBI和语句句柄 处境,perl,fork,dbi,Perl,Fork,Dbi,所以我知道连接在进程之间共享,我不能使用在子进程中的fork之前打开的连接 我还知道,当我尝试这样做时,perl会抱怨: my $sth = $dbConn->prepare($sql); $sth->execute(); $dbConn->disconnect(); while(my @row = $sth->fetchrow_array){ print @row,"\n"; } 因为我试图在语句句柄仍处于活动状态时断开连接 那么,为什么会

所以我知道连接在进程之间共享,我不能使用在子进程中的fork之前打开的连接

我还知道,当我尝试这样做时,perl会抱怨:

my $sth = $dbConn->prepare($sql);
$sth->execute();
$dbConn->disconnect();
while(my @row = $sth->fetchrow_array){
    print @row,"\n";
}
因为我试图在语句句柄仍处于活动状态时断开连接

那么,为什么会这样: 如果孩子在退出时关闭它,perl不应该抱怨语句句柄仍然处于活动状态吗?我还确保在循环完全迭代之前,某些进程的执行已经结束,并认为它可能会抱怨,但事实并非如此。我是否应该获取数组引用并使用它们进行迭代,而不是在本场景中演示的方法?

Update 您在上面的评论中说,子进程确实关闭父进程的数据库句柄,因此唯一的问题是为什么没有与关闭句柄相关联的关于仍处于活动状态的语句句柄的消息

这是因为在关闭数据库句柄之前,子进程还将首先在终止时关闭语句句柄,因此没有要报告的错误条件



你没有说你使用的是什么数据库驱动程序,我猜你只是碰巧有一个性能良好的数据库驱动程序

DBI
模块的文档说明了这一点

对于某些驱动程序,当子进程退出时,继承句柄的销毁会导致父进程中相应的句柄停止工作

因此,您使用的驱动程序可能不是这些驱动程序之一


另一种方法是,连接到数据库的代码设置
AutoInactiveDestroy
标志。它强制
DESTROY
方法检查当前PID是否与创建数据库和语句句柄的PID相同,无论如何,这是所有新代码的推荐做法

我可以重现这在5.20和Ubuntu上的效果。看起来它没有在退出时隐式调用
断开连接
,无论是在我尝试的sqlite的子级还是父级。如果您在孩子身上执行
$dbConn->disconnect
,它会抱怨。@simbabque我想知道为什么不会发生这种情况。如果在循环之后尝试使用dbConn,它会说“连接已消失”,这是有道理的,但如果发生这种情况,它也会抱怨循环中的迭代。你知道这样使用会不会有什么危险吗?好的,这很有道理,谢谢。然而,关于您的更新:为什么在第一个完成的子级退出时关闭语句句柄后循环会继续?@R6D1H2:我不知道。是否已检查是否已处理全套行?您的选择中是否有多行?或者,可能是在第一个子项退出后,
fetchrow\u数组
调用就悄无声息地失败了,如果语句句柄上的
DESTROY
只调用
finish
,就会发生这种情况。您应该检查
$sth->{Active}
以查看句柄的状态。是的,将处理整个行集。正如在文章中提到的,我甚至确保在循环完成之前进程退出,以准确测试这种情况。@R6D1H2:好的,那么我猜驱动程序会缓存整个
select
结果,并在调用
fetchrow
时将其分块传递回去。即使把手已经断开,这也可以工作。如果不知道我们在这里处理的是什么驱动程序,也不知道它是如何编码的,我就不能说更多了。@R6D1H2:你不应该使用这种方法。它没有文件记录,而且不可靠。建立连接时,应将
$dbConn->{AutoInactiveDestroy}=1
。这样,只有创建句柄的进程才会自动销毁它,并且在
while
循环之后,句柄将保持完整且可用。
my $sth = $dbConn->prepare($sql);
$sth->execute();
while(my @row = $sth->fetchrow_array){
    my $pid = fork; 
    if(not defined $pid){
        warn "Could not fork\n";
        next;  # abort loop
    }
    if($pid){
        #Parent: Do nothing
    }
    else{ 
        #do stuff
        exit;
    }
}