2013-06-22 66 views
0

我使用這篇文章:http://www.perlmonks.org/?node_id=594175來編寫代碼,將DBI和fork結合在一起。它適用於Linux,但不適用於Windows XP。我使用活動狀態Perl v5.10.0 MSWin32-x86-多線程,DBD :: mysql v4.011。DBI和fork不能在Windows上工作

在Linux上Perl v5.16.1 i486-linux-thread-multi DBD :: mysql v4.021。

代碼。 dbi_fork.pl:

#!/usr/bin/perl 

use strict; 
use warnings; 
use DBI; 
require "mysql.pl"; 

my $dbh = connect_mysql(); 

if (fork()) { 
    $dbh->do("UPDATE articles SET title='parent' WHERE id=1"); 
} 
else { 
    my $dbh_child = $dbh->clone(); 
    $dbh->{InactiveDestroy} = 1; 
    undef $dbh; 
    $dbh_child->do("UPDATE articles SET title='child' WHERE id=2"); 
} 

mysql.pl:

sub connect_mysql 
{ 
    my $user_db = 'user'; 
    my $password_db = 'secret'; 
    my $base_name = 'test'; 
    my $mysql_host_url = 'localhost'; 

    my $dsn = "DBI:mysql:$base_name:$mysql_host_url"; 
    my $dbh = DBI->connect($dsn, $user_db, $password_db) or die $DBI::errstr; 

    return $dbh; 
} 

1; 

文章表:

DROP TABLE IF EXISTS `articles`; 
CREATE TABLE `articles` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `title` varchar(50) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 

-- ---------------------------- 
-- Records of articles 
-- ---------------------------- 
INSERT INTO `articles` VALUES ('1', 'title1'); 
INSERT INTO `articles` VALUES ('2', 'title2'); 

在Windows上,給出了一個錯誤:

$ perl ./dbi_fork.pl 
DBD::mysql::db clone failed: handle 2 is owned by thread 2344b4 not current 
thread 1a45014 (handles can't be shared between threads and your driver may 
need a CLONE method added) at ./dbi_fork.pl line 14. 

如何解決?

+3

**(1)**你不能比較的行爲Windows版本與Linux版本;這裏有太多的變數。您可以通過在XP機器上安裝perl5.16(例如[Strawberry Perl](http://strawberryperl.com/))並安裝相同版本的DBD :: mysql來減少變量數量。 **(2)**無論如何,Windows沒有原生的'fork'。相反,它是使用線程來模擬的。看起來問題可以通過在叉子前克隆手柄並讓每個側面關閉未使用的手柄來解決。或者孩子重新運行'connect_mysql'來獲得第二個句柄。 – amon

+0

@amon:您應該將其作爲答案發布。 – Borodin

回答

4

在Windows上沒有這樣的東西,如fork。這是unix系統特有的功能。 Perl在Windows上使用線程來模擬它,這會導致問題。

與其嘗試重新創建現有連接,只需在任務中創建連接即可。

換句話說,使用

if (fork()) { 
    my $dbh = connect_mysql(); 
    $dbh->do(...); 
} else { 
    my $dbh = connect_mysql(); 
    $dbh->do(...); 
} 
+0

我沒有注意到你使用了一個奇怪的黑客來嘗試在子進程中創建一個新的連接 - 我想在我注意到你只連接了一次後,我停止付錢attn - 所以我的解釋有點偏離,但是解決方案仍適用。更新說明。 – ikegami

2

這裏是解決方案 - 每一個線程創建它自己的連接:

#!/usr/bin/perl 

use strict; 
use warnings; 
use DBI; 
require "mysql.pl"; 

if (fork()) { 
    my $dbh = connect_mysql(); 
    $dbh->do("UPDATE articles SET title='parent' WHERE id=1"); 
} 
else { 
    my $dbh = connect_mysql(); 
    $dbh->do("UPDATE articles SET title='child' WHERE id=2"); 
} 
+1

這是最好的方法。 –