【问题标题】:How to get a different handle using clone() on DB handle created by connect_cache?如何在 connect_cache 创建的 DB 句柄上使用 clone() 获得不同的句柄?
【发布时间】:2020-08-18 18:22:23
【问题描述】:

尊敬的评审团!

我发现 Perl DBI 的一个问题可能是错误或功能。我赌第一个。 :)

我发现$dbh->clone() 如果由DBI->connect_cached() 创建,则返回相同的$dbh

示例代码如下:

use strict;
use warnings;
use DBI 1.614;

my %attr = (PrintError => 1);
my @conn = ('DBI:Oracle:MYSERVER', 'Solaris', '****', \%attr);

print "#### Simple connect ############################################\n";

{
my $dbh1 = DBI->connect(@conn); print $dbh1,"\n";
my $dbh2 = DBI->connect(@conn); print $dbh2,"\n";
my $dbh3 = $dbh1->clone(\%attr); print $dbh3,"\n";
}

print "#### Cached connect ############################################\n";

{
my $dbh1 = DBI->connect_cached(@conn); print $dbh1,"\n";
my $dbh2 = DBI->connect_cached(@conn); print $dbh2,"\n";
my $dbh3 = $dbh1->clone(\%attr); print $dbh3,"\n";
}

print "#### Cached connect with private ###############################\n";

{
$attr{private_data} = 1;
my $dbh1 = DBI->connect_cached(@conn); print $dbh1,"\n";
$attr{private_data} = 2;
my $dbh2 = DBI->connect_cached(@conn); print $dbh2,"\n";
$attr{private_data} = 3;
my $dbh3 = $dbh1->clone(\%attr); print $dbh3,"\n";
}

print "#### END #######################################################\n";

输出是:

#### Simple connect ############################################
DBI::db=HASH(0x27ec838)
DBI::db=HASH(0x27ed138)
DBI::db=HASH(0x2b53638)
#### Cached connect ############################################
DBI::db=HASH(0x28863d8)
DBI::db=HASH(0x28863d8)
DBI::db=HASH(0x28863d8)
#### Cached connect with private ###############################
DBI::db=HASH(0x27ec880)
DBI::db=HASH(0x2b53e48)
DBI::db=HASH(0x27ec880)
#### END #######################################################
  • 简单的connect 按我的预期工作。新连接到同一服务/用户返回不同的 $dbh 和 clone() 类似。
  • 缓存连接也可以按预期工作。在所有 3 个案例中都返回了相同的 $dbh
  • 最后我应用了一个 private_* 属性,如connect_cached 中的文档所述。它仅适用于connect_cached 调用,但根据clone 的描述,为clone 提供唯一属性并没有像我预期的那样提供新的DBI 句柄。但也许我的期望是错误的。

真正的问题是我想实现一个fork() 证明解决方案。我为所有新创建的$dbhs 设置了AutoInactiveDestroy,一切正常,除了我无法在父进程中为connect_cached 创建的现有$dbh 获得唯一句柄,相反我设置了private_pid 属性等于当前进程的pid。我检查了DBI.pm 源,clone 调用了原始$dbh 的内部dbi_connect_closure,这个闭包基于原始$dbh 的connect 方法调用connectconnect_cached 方法。所以,我认为它应该考虑唯一的private_* 属性并返回一个新的$dbh

作为一种解决方法,我每次都调用connect_cashed,而不是调用clone

请分享任何可能有助于解决或解决问题的信息。

版本:

Perl : v5.26.2
DBI  : 1.641
Linux: 3.10.0-1127.el7.x86_64

提前致谢!没错

【问题讨论】:

  • @Pradeep 感谢您的提示! $dbh 是由其他模块创建的,所以我可以设置一些属性,但是我的代码没有完成连接。而且我无法安装新的 Perl 模块,因为环境不是我维护的。

标签: perl fork clone dbi


【解决方案1】:

我不是 DBI 专家。我试图查找 DBI clone() 代码,但这很快就涉及到 C/XS 细节,这让我有点不知所措:-)

我可以提出的一个建议是注意您的 %attr 哈希。您将对同一 %attr 的引用传递给每个 connect_cache()clone() 调用。这意味着,当您到达 $dbh3 句柄时,所有句柄都将使用 private_data = 3 引用相同的属性。

我假设clone() 将检查属性引用是否相同(如,指向相同的%attr 哈希)。如果是,clone() 将给您相同的句柄。

试试这个改变:

...
print "#### Cached connect with private ###############################\n";

{
$attr{private_data} = 1;
my $dbh1 = DBI->connect_cached(@conn); print $dbh1,"\n";
$attr{private_data} = 2;
my $dbh2 = DBI->connect_cached(@conn); print $dbh2,"\n";
my %dbh3_attr = ( PrintError => 1, private_data => 3 );
my $dbh3 = $dbh1->clone(\%dbh3_attr); print $dbh3,"\n";
}

print "#### END #######################################################\n";

我相信您会得到与上面报告的结果不同的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 2014-05-22
    • 1970-01-01
    • 2023-04-02
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多