代码之家  ›  专栏  ›  技术社区  ›  codeholic

在mod\u perl2下,使用fork和Apache::DBI的安全方法是什么?

  •  0
  • codeholic  · 技术社区  · 15 年前

    我在子进程中使用Apache::DBI时遇到了一个问题。问题是Apache::DBI为所有使用它的进程提供了一个句柄,因此

    DBD::mysql::db selectall\u arrayref 失败:命令不同步;你 此时无法运行此命令 /usr/local/www/apache22/data/test-fork.cgi

    重新连接没有帮助,因为Apache::DBI在所有进程中重新连接,正如我理解的以下错误

    错误,无法完成

    错误消息:DBD驱动程序尚未启动 在 /usr/local/lib/perl5/site\u 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;
    }
    

    2 回复  |  直到 15 年前
        1
  •  1
  •   Ether    15 年前

    我看到了一些选择:

    • 分叉时显式关闭DB句柄,并根据需要重新打开它们。

    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
    


    另外,在多进程环境中使用裸文件句柄时应该非常小心。你可以很容易地破坏你的数据。 open (my $fh, $file) or die "Cannot open $file: $!" 更安全。

    看到你用这个我也有点紧张 eval {} $@ . 你只是在掩盖错误,而不是处理错误,所以可能发生了比你意识到的更多的事情。检查结果值(或者更好,使用显式异常处理模块,例如 Try::Tiny use strict; use warnings; .

    DBI 在你的代码里。别那么做。如果您在启动文件中使用Apache::DBI(或任何您称之为引导文件的文件),您就不必包含DBI本身。我不能肯定,但我不确定是否调用了正确的包(我已经有一段时间没有看过Apache::DBI的guts了;它也许能帮你解决这个问题)。