有没有办法在 Perl 中本地化包 - 数据库处理问题?
Is there a way to localise a package in Perl - database handle issues?
我需要使用 DBI 实例化一个新的 $dbh。
我的对象在创建时通常有一个 $dbh。
当我尝试使用
创建一个新的 $dbh 时
my $dbh = MyLib::Connect();
并在执行一些数据库操作后
$dbh->disconnect();
我的下游代码的 $dbh 已关闭。有没有办法得到我想要的东西?我看过一些示例代码执行两个 DBI->connect(...) 调用,但使用相同的代码作为示例会产生相同的结果——就像 MyLib 正在缓存返回的 $dbh 值。
示例代码:
package MyLib;
sub DoConnect {
...
my $dbh = DBI->connect(...);
return($dbh)
}
package Object;
sub GetData {
my ($id) = @_;
my $dbh = MyLib::DoConnect(); # This should be separate
...
$dbh->commit()
$dbh->disconnect();
return($someData);
}
package AnotherObject;
sub DoSomething {
my ($self) = @_;
# $self had a dbh set on instantiation with MyLib::DoConnect();
my $newData = Object::GetData($self->id);
my $moreData = GetDataUsingDBH($self->dbh); # the dbh is closed!!!
}
我是否需要在不启动单独线程的情况下做可能的事情(我不能保证它会在调用 GetDataUsingDBH 之前完成)。我应该对外部程序进行系统调用以等待它完成吗?我的问题有道理吗?
您确定 DoConnect 正在调用 DBI->connect,而不是 DBI->connect_cached,或者其他正在缓存数据库句柄的东西吗?
如果是这样,我猜你已经加载了 Apache::DBI 并且 运行 在 mod_perl 下(或者至少设置了 $ENV{MOD_PERL}
),这会导致 DBI ->connect 以使用 Apache::DBI 缓存连接。
您可以告诉 DBI 不要 通过使用 dbi_connect_method
属性调用连接来做到这一点:
DBI->connect( $data_source, $username, $auth, {
'dbi_connect_method' => 'connect',
} );
(这将要求您将某些内容传递到您的 DoConnect 中,说明这就是您想要的)。
这是记录的方式;一种可能对您有用的未记录的方法是在本地设置 DBI 使用的变量作为该属性的默认值:
# This should be separate
my $dbh = do { local $DBI::connect_via = 'connect'; MyLib::DoConnect() };
(我想即使您在加载 DBI 时没有设置 $ENV{MOD_PERL}
也可能是您的代码已经将 $DBI::connect_via 设置为 'connect_cached' 或一些其他包,这给你带来了麻烦。)
另一种方法,如果您实际上不需要同时使用两个数据库句柄,则只需删除断开连接调用。当 $dbh 超出范围时,如果周围没有该数据库句柄的其他副本,它将被关闭;没有必要显式调用断开连接。
您描述的方法工作正常。
package MyLib;
use DBI qw( );
sub DoConnect {
return DBI->connect(
'dbi:SQLite:foo.sqlite3', undef, undef,
{ PrintError=>0, RaiseError=>1 },
);
}
package Object;
sub new {
my $class = shift;
my $self = bless({}, $class);
return $self;
}
sub GetData {
my $dbh = MyLib::DoConnect();
$dbh->disconnect();
}
package AnotherObject;
sub new {
my $class = shift;
my $self = bless({}, $class);
$self->{dbh} = MyLib::DoConnect();
return $self;
}
sub DoSomething {
my ($self) = @_;
return $self->{dbh}->selectrow_array("SELECT 'abc'");
}
package main;
my $ao = AnotherObject->new();
my $o = Object->new();
$o->GetData();
print $ao->DoSomething(), "\n";
输出:
abc
您没有提及的其他原因导致了问题。
我明白了。我将我的 DBH 设置为由可执行文件中的所有对象共享,因此我不必实例化一个 DBH 并将其手动传递给我的对象——这破坏了我实际需要执行此操作时预期的行为。
感谢大家的帮助 - 学到了很多东西。
我需要使用 DBI 实例化一个新的 $dbh。
我的对象在创建时通常有一个 $dbh。
当我尝试使用
创建一个新的 $dbh 时my $dbh = MyLib::Connect();
并在执行一些数据库操作后
$dbh->disconnect();
我的下游代码的 $dbh 已关闭。有没有办法得到我想要的东西?我看过一些示例代码执行两个 DBI->connect(...) 调用,但使用相同的代码作为示例会产生相同的结果——就像 MyLib 正在缓存返回的 $dbh 值。
示例代码:
package MyLib;
sub DoConnect {
...
my $dbh = DBI->connect(...);
return($dbh)
}
package Object;
sub GetData {
my ($id) = @_;
my $dbh = MyLib::DoConnect(); # This should be separate
...
$dbh->commit()
$dbh->disconnect();
return($someData);
}
package AnotherObject;
sub DoSomething {
my ($self) = @_;
# $self had a dbh set on instantiation with MyLib::DoConnect();
my $newData = Object::GetData($self->id);
my $moreData = GetDataUsingDBH($self->dbh); # the dbh is closed!!!
}
我是否需要在不启动单独线程的情况下做可能的事情(我不能保证它会在调用 GetDataUsingDBH 之前完成)。我应该对外部程序进行系统调用以等待它完成吗?我的问题有道理吗?
您确定 DoConnect 正在调用 DBI->connect,而不是 DBI->connect_cached,或者其他正在缓存数据库句柄的东西吗?
如果是这样,我猜你已经加载了 Apache::DBI 并且 运行 在 mod_perl 下(或者至少设置了 $ENV{MOD_PERL}
),这会导致 DBI ->connect 以使用 Apache::DBI 缓存连接。
您可以告诉 DBI 不要 通过使用 dbi_connect_method
属性调用连接来做到这一点:
DBI->connect( $data_source, $username, $auth, {
'dbi_connect_method' => 'connect',
} );
(这将要求您将某些内容传递到您的 DoConnect 中,说明这就是您想要的)。
这是记录的方式;一种可能对您有用的未记录的方法是在本地设置 DBI 使用的变量作为该属性的默认值:
# This should be separate
my $dbh = do { local $DBI::connect_via = 'connect'; MyLib::DoConnect() };
(我想即使您在加载 DBI 时没有设置 $ENV{MOD_PERL}
也可能是您的代码已经将 $DBI::connect_via 设置为 'connect_cached' 或一些其他包,这给你带来了麻烦。)
另一种方法,如果您实际上不需要同时使用两个数据库句柄,则只需删除断开连接调用。当 $dbh 超出范围时,如果周围没有该数据库句柄的其他副本,它将被关闭;没有必要显式调用断开连接。
您描述的方法工作正常。
package MyLib;
use DBI qw( );
sub DoConnect {
return DBI->connect(
'dbi:SQLite:foo.sqlite3', undef, undef,
{ PrintError=>0, RaiseError=>1 },
);
}
package Object;
sub new {
my $class = shift;
my $self = bless({}, $class);
return $self;
}
sub GetData {
my $dbh = MyLib::DoConnect();
$dbh->disconnect();
}
package AnotherObject;
sub new {
my $class = shift;
my $self = bless({}, $class);
$self->{dbh} = MyLib::DoConnect();
return $self;
}
sub DoSomething {
my ($self) = @_;
return $self->{dbh}->selectrow_array("SELECT 'abc'");
}
package main;
my $ao = AnotherObject->new();
my $o = Object->new();
$o->GetData();
print $ao->DoSomething(), "\n";
输出:
abc
您没有提及的其他原因导致了问题。
我明白了。我将我的 DBH 设置为由可执行文件中的所有对象共享,因此我不必实例化一个 DBH 并将其手动传递给我的对象——这破坏了我实际需要执行此操作时预期的行为。
感谢大家的帮助 - 学到了很多东西。