使用Class :: DBI时如何避免错误最大open_cursor超出

时间:2009-10-28 05:55:22

标签: perl

(更新以回答下面Jonathan Leffler提出的问题):

我们正在运行Perl 5.8.7和Oracle 11.1.0.7.0。

由于公司的政策,开发人员对软件升级没有任意控制。向高层管理人员提交建议需要数月才能得到跟进(如果获得批准) - 我想其他几家公司也不会出现奇怪的情况。

我从其他人离开公司继承了该程序,并从应用程序日志文件中发现了“发出rollback()...”的警告。运行 DBI_TRACE = 2 = / tmp / trace.log program_name.pl 后,找到了“超出最大open_cursor”的实际问题。

查看$ dbh-> {ActiveKids},$ dbh-> {Kids}和$ dbh-> {CachedKids}的数量,我假设最大打开游标为50,因为错误发生在它之后达到50。


我们的传统生产代码正在使用这些模块:

  • DBI - 1.48
  • Ima :: DBI - 0.33
  • Class :: DBI - 0.96
  • Class :: DBI :: Oracle - 0.51
  • DBD :: Oracle - 1.16

出于某些奇怪的政策原因,无法将模块升级到更新版本:(

应用程序依赖于使用CDBI来处理大量表的关系。代码的简化代码如下:

JOB:
foreach my $job (@jobs) {
  my @records = $job->record; 

  RECORD: 
  foreach my $record (@records) {
      my @datas = $record->data;

      DATA:
      foreach my $data (@datas) {
          ....
      }
  }
}

其中每个 @jobs $ record $ data 是表的对象,而最内层循环调用其他几个触发器

在几个循环后的某个地方我收到一个Oracle错误:超出最大open_cursor 然后我从CDBI得到错误:发出rollback()数据库句柄被DESTROYE'd没有显式断开连接

我可以通过 undef - 最外层循环上的DBI CachedKids来解决它:

# somewhere during initialization
$self->{_this_dbh} = __PACKAGE__->db_Main();

....

JOB:
foreach my $job (@jobs) {
    RECORD: ....
        DATA: ....

    $self->{_this_dbh}->{CachedKids} = undef;
}

这是正确的方法吗?

或者CDBI是否支持以与DBI $ sth-> finish()相同的方式清除语句句柄?

感谢。

1 个答案:

答案 0 :(得分:2)

在某些时候,您必须解释为什么无法升级到更接近当前版本的软件。您没有提到您使用的是哪个版本的Perl,或者是哪个版本的Oracle;不知何故,我怀疑它既不是5.10.1也不是11gR2。

当前版本:

  • Class :: DBI 3.0.17
  • Class :: DBI :: Oracle 0.51
  • DBI 1.609(版本1.48来自2005年)
  • DBD :: Oracle 1.23(版本1.16来自2004年)
  • Ima :: DBI 0.35

最近发生了什么变化?为什么你突然发现一个大概是非常稳定的软件问题?这是新代码吗?

使用普通的DBI,当你取消一个语句句柄(例如,让它超出范围)时,与它相关的资源会被释放 - 或多或少吵闹。但是,Class :: DBI和DBI之间有足够的基础设施,很难说它是如何映射的。

  • 你有没有弄清楚开放游标的限制是什么?
  • 您是否已经确定是否已经打开足够的游标以超过该限制?
  • 您是否尝试过在环境中设置DBI_TRACE?像3这样的值会告诉你相当多的东西 - 可能太多了。它将显示游标是否正确释放。
  • 您是否尝试过减少在单个会话中操作的表的数量?
  • 您是否考虑过在操作表之间断开连接并重新连接?
  • 有没有办法到达对应于Class :: DBI抽象的语句句柄,这样你实际上可以执行$ sth-> finish()?