【问题标题】:ORA-01000: maximum open cursors exceededORA-01000: 超出最大打开游标
【发布时间】:2011-08-14 16:18:47
【问题描述】:

使用 Delphi 7、BDE 和 Oracle

我执行一个 SQL 选择语句,然后单步执行返回集的每条记录,并执行以下更新 sql

var
 AQuery: TQuery;
begin
 AQuery:= TQuery.Create(nil);
 AQuery.DatabaseName:= ADatabase.DatabaseName;
 with AQuery do
 begin
  SQL.Text:= 'UPDATE AP_Master SET CMCL_FORECAST_CLEARED=:AClearedDate WHERE ID=:AMasterId';
  ParamByName('AMasterId').AsString:= IntToStr(AId);
  ParamByName('AClearedDate').AsDateTime:= StrToDateTime(FormatDateTime('mm/dd/yyyy', AForeCastClearedDate));
  try
   ExecSql;
  except on E: Exception do
   begin
    raise Exception.create('Error Updating AP_Master Tables Forecast Cleared Date!' + E.Message);
   end;//except
  end; //try
 end; //with
 AQuery.Close;
 AQuery.Free;
end;

它适用于 forst 500 + 记录,但我得到一个:ORA-01000: maximum open cursors exceeded 消息

我需要在 BDE 端、oracle 端还是在我的代码中做些什么(我使用标准 TQuery 和 TDatabase 组件)

【问题讨论】:

  • 您至少应该将 Close() 和 Free() 放在 try/finally 块中。但我不指望这能解决问题。
  • ParamByName('AMasterId').AsString:= IntToStr(AId);可以简单地写成 ParamByName('AMasterId').AsInteger:= AId;也许你可以对日期做同样的事情。为什么要获取日期,将其转换为字符串,然后获取该字符串并将其转换为日期?如果您只需要获取日/月/年部分,则有更好的方法(即 Trunc())。
  • @ldsandon:我得到了日期的东西,但错过了 IntToStr 。我已经在我的答案中更正了我的代码以反映这一点。谢谢。
  • 另外,您是通过 BDE 使用 SQL 链接还是通过 ODBC 连接?如果 ODBC 是 Oracle ODBC 还是 Microsoft ODBC for Oracle?版本?

标签: oracle delphi delphi-7


【解决方案1】:

您对查询的关闭不合适,这意味着您正在孤立每一行的游标。试试这个:

var
 AQuery: TQuery;
begin
  AQuery:= TQuery.Create(nil);
  try
    AQuery.DatabaseName:= ADatabase.DatabaseName;

    with AQuery do
    begin
      SQL.Text:= 'UPDATE AP_Master'#13 +
                 'SET CMCL_FORECAST_CLEARED = :AClearedDate'#13 +
                 'WHERE ID= :AMasterId';
      ParamByName('AMasterId').AsInteger := AId;
      // Note the date->string->date is not necessary; setting the param
      // AsDateTime with a TDateTime value will format it correctly for you.
      ParamByName('AClearedDate').AsDateTime:= AForeCastClearedDate;

      try // Protect open
        try
          ExecSql;
          except 
           on E: Exception do
             raise Exception.create('Error Updating AP_Master Tables' +
                                    ' Forecast Date Cleared' +
                                    E.Message);   
          end;//except
        end; // except try
      finally
        AQuery.Close;  // finally means it's closed every time always
      end; //finally try for opening
    end; //with
  finally
    AQuery.Free;  // finally here ensures free
  end;
end;

【讨论】:

  • 不正确。我上面发布的代码是一个例程。我通过 select sql 返回集循环,为每条记录调用例程。因此,如果您查看我在上面发布的代码,对于选择中的每条记录,都会调用上面的代码(或调用该例程)。查询被创建、执行、关闭和释放,循环转到 select 语句中的下一条记录并执行例程(上面的代码)。
  • Shane,您在发表评论之前尝试过 Ken 的回答吗?我相信这是您问题的解决方案。顺便说一句,Except后面的代码不会执行。
  • 那么您未能发布显示它是函数/过程的代码部分。 (您的问题也没有提及。)“遍历返回集的每条记录并执行以下更新 sql” - 这对我来说就像一个循环,并且没有任何其他方式知道我的答案是什么基于。
  • 如果遇到异常,您仍然会跳过 Close/Free 调用。如果您在异常处理程序中重新引发异常,它将使代码“跳转”到外部异常处理程序。此外,如果这是为外部循环的每条记录调用的函数,则效率非常低,您可以创建一次查询,然后重新执行它,仅更改参数。更好的是,您可以使用单个查询来执行整个更新,而无需循环客户端。
  • @Shane 一旦释放所有会话或重新启动您的电脑,然后尝试 Ken 的解决方案
猜你喜欢
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-24
相关资源
最近更新 更多