我需要使用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之前完成),我需要做什么。我应该对外部程序进行系统调用以等待它完成吗?我的问题是否有意义?
答案 0 :(得分:3)
您描述的方法运行正常。
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
你没有提到的其他事情导致问题。
答案 1 :(得分:0)
我明白了。我将我的DBH设置为由可执行文件中的所有对象共享,因此我不必实例化一个DBH并将其手动传递给我的对象 - 这破坏了我实际需要执行此操作时所期望的行为
感谢你们所有的帮助,伙计们 - 学到了很多。
答案 2 :(得分:-1)
您确定DoConnect是在调用DBI-> connect,而不是DBI-> connect_cached,还是其他缓存数据库句柄的东西?
如果是这样,我猜你已经加载了Apache :: DBI并且在mod_perl下运行(或者无论如何都设置了$ENV{MOD_PERL}
),这导致DBI-> connect使用Apache :: DBI缓存连接。
您可以通过调用带有dbi_connect_method
属性的连接来告诉DBI 不这样做:
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超出范围时,如果没有该数据库句柄的其他副本,它将被关闭;明确要求断开连接是不必要的。