我在子进程中使用Apache :: DBI时遇到问题。问题是Apache :: DBI为使用它的所有进程提供了一个句柄,所以我得到了
DBD :: mysql :: db selectall_arrayref 失败:命令不同步;您 现在无法运行此命令 /usr/local/www/apache22/data/test-fork.cgi 第20行。
重新连接没有帮助,因为Apache :: DBI在所有进程中重新连接,因为我理解以下错误
服务器遇到内部问题 错误,无法完成您的 请求。
错误消息:DBD驱动程序没有 实现了AutoCommit属性 在 /usr/local/lib/perl5/site_perl/5.8.9/Apache/DBI.pm 第283行,
这是原始代码:
use Data::Dumper 'Dumper';
use DBI ();
my $dbh = DBI->connect($dsn, $username, $password, {
RaiseError => 1,
PrintError => 0,
});
my $file = "/tmp/test-fork.tmp";
my $pid = fork;
defined $pid or die "fork: $!";
if ($pid) {
my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') };
print "Content-Type: text/plain\n\n";
print $rows ? "parent: " . Dumper($rows) : $@;
}
else {
my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') };
open FH, '>', $file or die "$file: $!";
print FH $rows ? "child: " . Dumper($rows) : $@;
close FH;
}
我用于重新连接的代码:
...
else {
$dbh->disconnect;
$dbh = DBI->connect($dsn, $username, $password, $attrs);
my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') };
open FH, '>', $file or die "$file: $!";
print FH $rows ? "child: " . Dumper($rows) : $@;
close FH;
}
有没有一种安全的方法可以使用Apache :: DBI进行分叉?有没有办法让它创建一个新的连接呢?
答案 0 :(得分:1)
我看到了几个选项:
e.g:
my $dbh = DBI->connect(...);
my $pid = fork;
defined $pid or die "fork: $!";
if ($pid) {
# parent...
}
else {
# child...
undef $dbh;
通过将$dbh
存储在对象中,并根据需要将该对象传递给系统的某些部分,可以使这更容易。该对象将负责根据需要重新打开$ dbh,因此应用程序的其余部分不必关心细节。保持代码封装并与系统的其他部分完全分离。
我在我的系统中使用了一个Moose对象中的DBIx :: Connector,它使用方法委托来提供dbh。该应用程序只是:
my $dbh = $db_dbj->dbh;
my $sth = $dbh->prepare(...);
# more boring DBI code here
......并且根据需要无形地重新连接/重新生成dbh。
另外,您应该非常小心在多进程环境中使用裸文件句柄。你可能很容易破坏你的数据。 open (my $fh, $file) or die "Cannot open $file: $!"
更加安全。
看到你使用eval {}
块而不检查$@
的内容,我也有些紧张。你只是掩盖错误,而不是处理它们,所以可能会发生比你所知更多的事情。检查结果值(或更好,使用显式异常处理模块,例如Try::Tiny。使用use strict; use warnings;
。
PS。我刚刚注意到您在代码中明确包含DBI
。不要那样做。如果你在startup_modperl.pl中使用Apache :: DBI(或者你称之为引导程序文件),你就不应该包含DBI本身。我不能肯定地说,但我不相信正确的包被调用(自从我查看Apache :: DBI的内容以来已经有一段时间了;它可能会为你解决这个问题。)
答案 1 :(得分:0)
不要在mod_perl2下分叉。使用Apache2::Subprocess。另请参阅Is it a bad idea to fork under mod_perl2?