ما هي الطريقة الآمنة لاستخدام الشوكة مع Apache :: DBI تحت mod_perl2؟

StackOverflow https://stackoverflow.com/questions/2551682

سؤال

لدي مشكلة عندما أستخدم Apache :: DBI في عمليات الطفل. المشكلة هي أن Apache :: DBI يوفر مقبضًا واحدًا لجميع العمليات التي تستخدمه ، لذلك أحصل

DBD :: MySQL :: DB Selectall_arrayref فشل: أوامر من المزامنة ؛ لا يمكنك تشغيل هذا الأمر الآن على /usr/local/www/apache22/data/test-fork.cgi الخط 20.

لا تساعد إعادة الاتصال ، لأن Apache :: DBI تقوم بإعادة الاتصال في جميع العمليات ، كما فهمت الخطأ التالي

واجه الخادم خطأ داخليًا ولم يتمكن من إكمال طلبك.

رسالة الخطأ: لم ينفذ برنامج تشغيل DBD سمة AutoCommit AT /USR/LOCAL/LIB/PERL5/SITE_PERL/5.8.9/APACHE/DBI.PM LINE 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 مع Forking؟ هل هناك طريقة لجعلها إنشاء اتصال جديد ربما؟

هل كانت مفيدة؟

المحلول 2

لا تافهة تحت mod_perl2. يستخدم Apache2 :: Subprocess. أنظر أيضا هل هي فكرة سيئة أن تتطرق تحت mod_perl2؟

نصائح أخرى

أرى بعض الخيارات:

  • أغلق صراحة مقابض DB الخاصة بك عند شوطك ، وإعادة فتحها حسب الحاجة.

على سبيل المثال:

my $dbh = DBI->connect(...);

my $pid = fork;
defined $pid or die "fork: $!";

if ($pid) {
    # parent...
}
else {
    # child...
    undef $dbh;

يمكن أن يكون هذا أسهل عن طريق تخزين $dbh في كائن ، وتمرير هذا الكائن حسب الحاجة إلى أجزاء من نظامك. سيكون الكائن مسؤولاً عن إعادة فتح $ DBH حسب الحاجة ، وبالتالي فإن بقية التطبيق لا يجب أن تهتم بالتفاصيل. حافظ على رمز مغلف ومفصل جيدًا من أجزاء أخرى من النظام.

يمكنني استخدام DBIX :: Connector في نظامي داخل كائن Moose ، والذي يستخدم تفويض الطريقة لتوفير DBH. التطبيق ببساطة:

my $dbh = $db_dbj->dbh;
my $sth = $dbh->prepare(...);
# more boring DBI code here

... ويتم إعادة توصيل/تجديد DBH حسب الحاجة ، بشكل غير مرئي.


جانبا ، يجب أن تكون حذرا حقا من استخدام FileHandles العارية في بيئة متعددة المعالجة. يمكن أن تكون سهلة للغاية في تحطيم بياناتك. open (my $fh, $file) or die "Cannot open $file: $!" أكثر أمانًا.

أنا أيضًا متوتر قليلاً من خلال رؤيتك تستخدم eval {} كتل دون التحقق من محتويات $@. أنت مجرد إخفاء الأخطاء ، بدلاً من التعامل معها ، لذلك قد يكون هناك أشياء أكثر مما تدرك. تحقق من قيمك (أو أفضل ، استخدم وحدة معالجة الاستثناءات الصريحة ، مثل حاول :: صغير. استعمال use strict; use warnings;.

ملاحظة. لقد لاحظت للتو أنك تضم بشكل صريح DBI في الكود الخاص بك. لا تفعل ذلك. إذا كنت تستخدم Apache :: DBI في Startup_modperl.pl (أو أي شيء تسميه ملف bootstrap الخاص بك) ، يجب ألا تضطر أبدًا إلى تضمين DBI نفسه. لا أستطيع أن أقول بالتأكيد ، لكنني لن أكون واثقًا من أن الحزمة الصحيحة يتم استدعاؤها (لقد مر بعض الوقت منذ أن نظرت إلى شجاعة Apache :: DBI ؛ قد يعتني بذلك لك).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top