ما هي الطريقة الآمنة لاستخدام الشوكة مع Apache :: DBI تحت mod_perl2؟
-
23-09-2019 - |
سؤال
لدي مشكلة عندما أستخدم 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 حسب الحاجة ، وبالتالي فإن بقية التطبيق لا يجب أن تهتم بالتفاصيل. حافظ على رمز مغلف ومفصل جيدًا من أجزاء أخرى من النظام.
- لا تستخدم Apache :: DBI. أستطيع أن أوصي بشدة DBIX :: موصل, ، الذي يفتح اتصالًا جديدًا حسب الحاجة ولا يحافظ على السلوك السيئ لأي من السهل DBI أو Apache :: DBI: انظر http://search.cpan.org/~dwheeler/dbix-connector-0.32/lib/dbix/connector.pm#description للحصول على وصف مفصل لكيفية اختلافها.
يمكنني استخدام 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 ؛ قد يعتني بذلك لك).