某些会话导致ORA-29471,因为dbms_sql无法用于这些会话。我们在应用程序中遇到此错误的记录很少。
如何解决这个问题? 我们如何识别特定会话无法访问DBMS_SQL?我们在会话级别有任何属性/标志吗?
以下链接提供了一种在本地重现此问题的方法。 Reproduce
答案 0 :(得分:3)
错误发生在运行时。你可能无法猜测它会在它发生之前发生。也许您的解决方案是使用要打开的游标ID进行单个块检查{.1}}。
但如果您正在寻找这个,那么如何找到已打开游标列表:
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
希望这可以帮助您调整某些内容以检查是否使用了预期的光标。
答案 1 :(得分:3)
正式地说,一旦提出了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;
/
答案 2 :(得分:2)
当给定的游标参数未被DBMS_SQL
打开或已经关闭时,会发生错误。一个可能的原因可能是应用程序打开游标并将其传递给其他一些代码。然后其他代码关闭游标并返回到您的应用程序,该应用程序现在不再访问该关闭的游标。
如果您的实际代码没有任何代码段失败,将很难为您提供帮助。但是,要调试此查找会话中的第一个此错误实例,并查看传递到DBMS_SQL
的游标号。该光标号码不正确。
请注意,发生此错误后,该会话的DBMS_SQL
状态无效。换句话说,不允许在该会话中随后执行DBMS_SQL
并且将引发相同的错误。这样做是出于安全目的:例如,某些恶意代码可能试图抓住您的光标以暴露敏感数据。 DBMS_SQL
将发出此错误,然后锁定,以防止恶意代码遭受任何其他恶意SQL攻击。您必须重新连接,因此清除整个会话状态并踢出恶意代码,才能再次DBMS_SQL
访问。其他同时运行的会话不受此影响。他们继续在自己的私人和安全会话状态下正常运作。
答案 3 :(得分:2)
oracle errorstack可以帮助你。
像这样:更改系统设置事件' 29471跟踪名称errorstack level 1';
如果真的发生了ora-29471,
信息将打印在警报日志中,并附带相关的诊断跟踪文件。
在诊断跟踪文件中,
您可以轻松获取所需的信息。