【问题标题】:Trouble shooting ora-29471ora-29471 疑难解答
【发布时间】:2018-09-06 14:26:24
【问题描述】:

某些会话会导致 ORA-29471,因为 dbms_sql 无法用于这些会话。我们在申请中遇到了这个错误,记录很少。

如何解决这个问题? 我们如何识别特定会话对 DBMS_SQL 没有访问权限?我们在会话级别有任何属性/标志吗?

以下链接提供了一种在本地重现此问题的方法。 Reproduce

【问题讨论】:

  • 重现链接针对具有已接受答案的问题。是什么让你的问题与众不同?您需要提供更多详细信息。一些使用 dbms_sql 和记录错误的代码(假设您捕获并记录它们)将是一个很好的起点!

标签: oracle plsql oracle11g database-administration


【解决方案1】:

错误发生在运行时。您可能无法在它发生之前就猜到它会发生。也许您的解决方案是使用您要打开的光标 ID dbms_sql.is_open(c_id) 进行单个块检查。

但如果这是您要查找的内容,以下是如何找到 打开的游标列表

select a.value, s.username, s.sid, s.serial#
  from v$sesstat a, v$statname b, v$session s
 where a.statistic# = b.statistic#  and s.sid=a.sid
   and b.name = 'opened cursors current'
;

您也可以访问v$open_cursor 来统计它们:

SELECT *
  FROM v$open_cursor oc, v$session s
 WHERE oc.sid = s.sid
order by 3,2;

希望这可以帮助您调整某些内容以检查是否使用了预期的光标。

【讨论】:

    【解决方案2】:

    正式地,一旦引发 ORA-29471,您的会话就不能再次使用 DBMS_SQL。

    https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sql.htm#i1026408

    ORA-29471 DBMS_SQL 访问被拒绝:如果游标无效,则会引发此问题 检测到 ID 号。一旦会话遇到并报告 此错误,同一会话中的每个后续 DBMS_SQL 调用都会 引发此错误,这意味着 DBMS_SQL 对此不可操作 会话。

    实际上,您可以使用 dbms_session.modify_package_state 来清除所有包的会话状态、关闭所有打开的游标等。根据您的情况,这可能比删除/打开数据库连接更易于管理。

    declare
      c_1 number := 5;
      l_res boolean;
    begin
      l_res := dbms_sql.is_open(c_1);
    end;
    /
    
    declare
      c_2 number;
    begin
      c_2 := dbms_sql.open_cursor();
    end;
    /
    
    begin
     dbms_session.modify_package_state(dbms_session.reinitialize);
    end;
    /
    
    declare
      c_2 number;
    begin
      c_2 := dbms_sql.open_cursor();
    end;
    /
    

    【讨论】:

      【解决方案3】:

      当给定的游标参数不是由DBMS_SQL 打开或者已经关闭时,就会发生错误。一种可能的原因可能是应用程序打开了游标并将其传递给其他代码。然后其他代码关闭游标并返回到您的应用程序,该应用程序现在无法再访问该关闭的游标。

      如果您的实际代码没有任何 sn-ps 失败,那么将很难为您提供帮助。但是,要调试此错误,请在会话中查找此错误的第一个实例,并查看传递给DBMS_SQL 的游标号。那个光标编号不正确。

      请注意,发生此错误后,该会话的DBMS_SQL 状态将失效。换句话说,不再允许在该会话中执行 DBMS_SQL 的后续操作,并且将引发相同的错误。这样做是出于安全目的:例如,某些恶意代码可能试图抓住您的光标以暴露敏感数据。 DBMS_SQL 将发出此错误然后锁定,以防止恶意代码受到任何其他恶意 SQL 攻击。您必须重新连接,从而清除整个会话状态并踢出恶意代码,才能再次获得DBMS_SQL 访问权限。其他同时运行的会话不受此影响。它们继续在自己的私有和安全会话状态下正常运行。

      【讨论】:

        【解决方案4】:

        oracle 错误堆栈可能会对您有所帮助。

        像这样:

        alter system set events '29471 trace name errorstack level 1';

        如果ora-29471真的发生了,

        该信息将与相关的诊断跟踪文件一起打印在警报日志中。

        在诊断跟踪文件中,

        您可以轻松获得所需的信息。

        【讨论】:

          猜你喜欢
          • 2013-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-29
          • 2011-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多