探查“ORA-01000:超出最多允许打开的游标数”
问题描述
oracle 使用 OPEN_CURSORS 参数指定一个会话一次最多可以打开的游标的数量。超过此数量时,Oracle 将报告 orA-01000 错误。当此错误传播到 WebLogic Server 时,就会抛出 SQLException。
java.sql.SQLException: orA-01000: maximum open cursors exceeded
本模式阐述在使用 WebLogic Server 时出现该错误的可能成因及解决办法。
故障排除
请注意,并非下面所有任务都需要完成。有些问题仅通过执行几项任务就可以解决。
快速链接
诊断查询
常见成因及解决办法
代码惯例
Statement 缓存
数据库驱动程序
诊断查询
以下 SQL 查询有助于诊断 orA-01000 问题。要执行这些查询,需要以管理员身份登录数据库,或获得数据库管理员从那些 v$ 视图中进行选择的授权。
1. 检查数据库中的 OPEN_CURSORS 参数值。
oracle 使用 init.ora 中的初始化参数 OPEN_CURSORS 指定一个会话一次最多可以拥有的游标数。缺省值为 50。遗憾的是,此缺省值通常对 WebLogic Server 这样的系统来说过小。要获得数据库中 OPEN_CURSORS 参数的值,可以使用以下查询:
SQL> show parameter open_cursors;
NAME TYPEVALUE
------------------------------------ ----------- ---------------
open_cursors integer 1000
重要的是将 OPEN_CURSORS 的值设置得足够大,以避免应用程序用尽所有打开的游标。应用程序不同,该值也不同。即便会话打开的游标数未达 OPEN_CURSORS 指定的数量(即设置的值高于实际需要的值),也不会增加系统开销。
2. 获取打开的游标数。
下面的查询按降序显示用户“SCOTT”为每个会话打开的游标数。
SQL> select o.sid, osuser, machine, count(*) num_curs
2from v$open_cursor o, v$session s
3where user_name = 'SCOTT' and o.sid=s.sid
4group by o.sid, osuser, machine
5 order bynum_curs desc;
SID OSUSER MACHINE NUM_CURS
-----------------------------------------------------
217 m11000
96 m210
411 m310
50test9
在 WebLogic Server 中使用连接池时,此查询中的 user_name 应为用于创建连接池的 user_name(假定是从连接池得到连接)。该查询结果还给出了计算机名称。请在查询结果中找出打开游标数量大的 SID 和运行 WebLogic Server 的计算机的名称。
请注意,v$open_cursor 可以跟踪会话中 PARSED 和 NOT CLOSED 的动态游标(使用 dbms_sql.open_cursor() 打开的游标)。它不会跟踪未经分析(但已打开)的动态游标。在应用程序中使用动态游标并不常见。本模式的前提是未使用动态游标。
3. 获取为游标执行的 SQL。
使用在以上查询结果中找到的 SID 运行下面的查询:
SQL> select q.sql_text
2from v$open_cursor o, v$sql q
3where q.hash_value=o.hash_value and o.sid = 217;
SQL_TEXT
------------------------------------------------------------------------------------------------------------------------
select * from empdemo where empid='212'
select * from empdemo where empid='321'
select * from empdemo where empid='947'
select * from empdemo where empid='527'
...
结果将显示正在连接上执行的查询。它提供了一个入手点,让您可以反向跟踪到打开游标的来源。
返回页首
常见成因及解决办法
下面是查找问题成因及可能的解决办法的步骤。
代码惯例
此问题的最常见成因是未正常关闭 JDBC 对象。使用诊断查询中第三个查询的结果在应用程序代码中反向跟踪,确保将所有 JDBC 对象都正常关闭。BEA 建议在 finally 块中显式关闭 Connection、Statement 和 ResultSet 等 JDBC 对象,以确保无论是在正常还是异常情况下都将所有 JDBC 对象关闭。下面是一个常规示例:
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = getConnection(); //Method getConnection will return a JDBC Connection
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from empdemo");
// do work
} catch (Exception e) {
// handle any exceptions
} finally {
try {
if(rs != null)
rs.close();
} catch (SQLException rse) {}
try {
if(stmt != null)
stmt.close();
} catch (SQLException sse) {}
try {
if(conn != null)
conn.close();
} catch (SQLException cse) {}
}
请避免采用任何放弃 JDBC 对象的代码惯例。下面的代码惯例在每个循环迭代中都获得一个新的 Connection、Statement 和 ResultSet,但它没有关闭每个迭代的 JDBC 对象。因此,它会导致 JDBC 对象泄漏。
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String[] queries = new String[10];
//Define queries
try {
for(int i = 0; i < 10; i++) {
conn = getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery(queries[i]);
// do work
}
} catch (Exception e) {
// handle any exceptions
} finally {
try {
if(rs != null)
rs.close();
} catch (SQLException rse) {}
try {
if(stmt != null)
stmt.close();
} catch (SQLException sse) {}
try {
if(conn != null)
conn.close();
} catch (SQLException cse) {}
}
尽管根据 JDBC 规范的规定,关闭 Connection 时正常情况下也会将 Statement 和 ResultSet 关闭,但好的做法是:如果在一个 Connection 对象上创建了多个 Statement,则在使用完 Statement 和 ResultSet 后立即显式将它们关闭。如果未立即显式关闭 Statement 和 ResultSet,游标可能会积聚并在关闭 Connection 前超过数据库允许的最大数量。例如,在以下代码片断中,正常情况下通过 finally 块关闭 Connection 时,也会将 ResultSet 和 Statement 关闭。不过,此代码片断在一个连接上创建了多个 Statement 和 ResultSet。因此在循环完成前,可能已发生“超出最多允许打开的游标数”问题。
Connection conn = null;
try{
conn = getConnection();
for(int i = 0; i < NUM_STMT; i++) {
Statement stmt = null;
ResultSet rs = null;
stmt = conn.createStatement();
rs = stmt.executeQuery(/*some query*/);
//do work
}
} catch(SQLException e) {
// handle any exceptions
} finally {
try{
if(conn != null)
conn.close();
} catch(SQLException ignor) {}
}
返回页首
语句缓存
为提高性能,WebLogic Server 提供了一种功能,让您可以在使用连接池时将预处理语句和可调用语句载入缓存。当 WebLogic Server 将预处理语句或可调用语句载入缓存时,在许多情况下,DBMS 将为每个打开的语句都保留游标。因此,语句缓存可能是“超出最多允许打开的游标数”问题的成因。“语句缓存大小”属性决定在每个连接池实例中为每个连接缓存的预处理和可调用语句的总数。如果缓存的语句过多,可能会导致超过数据库服务器上打开游标数的上限。
请注意,各版本 WebLogic Server 的缺省语句缓存大小是有差异的。示例:
在 WebLogic Server 6.1 中,缺省的预处理语句缓存大小为 0 (http://e-docs.bea.com/wls/docs61/adminguide/jdbc.html#1133404 (English))。
在 WebLogic Server 7.0 中,非 XA 和 XA 预处理语句的缺省缓存大小为 5/语句 (http://e-docs.bea.com/wls/docs70/adminguide/jdbc.html#1144702 (English))。
在 WebLogic Server 8.1 中,预处理语句和可调用语句的缺省缓存大小合计为 10 (http://e-docs.bea.com/wls/docs81/ConsoleHelp/jdbc_connection_pools.html#1107805 (English))。
此外,在不同的 WebLogic Server 版本中,语句缓存的连接池属性名称和缓存算法的可配置性是不同的(有关详细信息,请参阅文档)。因此,如果最近对旧版本 WebLogic Server 进行了升级,语句缓存的行为变化可能会影响打开游标的数量。请将这种情况考虑在内。
要确定“超出最多允许打开的游标数”问题是否与语句缓存有关,可以通过将语句缓存大小设置为 0 将此功能关闭或减少缓存大小,再确认是否仍会出现错误。如果在减少缓存大小后问题没有发生,则说明连接池原有的语句缓存过大或 DBMS 中打开游标数的上限过低。可能需要考虑调整其中的一个值。如果发现连接上打开的游标数持续增加,但在将语句缓存大小设置为 0 后没有出现这种现象,则可能说明存在游标泄漏问题。这可能是由使用的 JDBC 驱动程序所致,也可能是 WebLogic Server 本身的一个错误。请尝试使用其它 JDBC 驱动程序。如果使用其它 JDBC 驱动程序后仍发生同样的问题,请将此问题报告给 BEA,这样支持工程师可以对问题做进一步探查,以确定该问题是否为 WebLogic Server 自身的一个错误。
返回页首
数据库驱动程序
“超出最多允许打开的游标数”问题的另一个可能成因是 JDBC 驱动程序有问题。为分清问题是驱动程序问题还是 WebLogic 连接池问题,如果有可重现的测试案例,可以尝试执行以下步骤。
1. 直接从驱动程序获取连接。
在测试案例中,绕过 WebLogic 连接池直接从驱动程序获取 JDBC 连接。但请不要关闭连接,只需让它们以数组或某种其它结构形式保持打开状态,然后确认游标泄漏是否仍然存在。不关闭连接是因为要模拟使用连接池时的行为。使用连接池时,connection.close() 并未真正地关闭物理连接,而是将连接返回到池中。
2. 尝试使用其它 JDBC 驱动程序。
可以尝试使用其它供应商的 JDBC 驱动程序或升级版的驱动程序,然后确认问题是否仍然存在。可以使用元数据来验证所使用的驱动程序是否正确。示例代码与下面的类似:
Connection conn = getConnection();
DatabaseMetaData dmd = conn.getMetaData();
System.out.println("JDBC Driver Name is " + dmd.getDriverName());
System.out.println("JDBC Driver Version is " + dmd.getDriverVersion());
3. XA 驱动程序错误。
如果使用的是 oracle XA 驱动程序,并且数据库中出现了大量类似“Select count (*) FROM SYS.DBA_PENDING_TRANSACTIONS”的查询,则可能是 oracle XA 驱动程序存在游标泄漏问题。在有关 MetaLink 的案例 3151681 中有对此问题的描述,并且版本 10.1.0.2 中已修正了该问题。
此外,在使用 XA 驱动程序时,请确保按在 http://e-docs.bea.com/wls/docs81/jta/thirdpartytx.html#1075181 (English) 中所述,在 Database Server 上启用 XA(例如,grant select on dba_pending_transactions to public)。
如果问题是 JDBC 驱动程序问题,但又不得不使用该驱动程序,一种以变通方式解决游标泄漏问题的方法是不时重设 WebLogic 连接池,或收缩连接池。有关重设或收缩连接池的方法,请参阅 WebLogic 文档(如果是 8.1 版本,该文档位于 http://e-docs.bea.com/wls/docs81/ConsoleHelp/domain_jdbcconnectionpool_control.html (Enlish))。
返回页首
已知问题
您可以定期查看所用 WLS 版本的“Release Notes”,了解 Service Pack 中的“Known Issues”或“Resolved Issues”的详细信息及浏览与 orA-01000 /游标泄漏有关的问题。方便起见,下面提供了这些发行说明的链接:
WLS 8.1 Release Notes (English)
WLS 7.0 Release Notes (English)
WLS 6.1 Release Notes (English)
对于需要特别注意之处,请参阅以下 CR,在相应版本 Service Pack 的发行说明中注明了已有针对它们的解决方法:
CR129379 - 如果 EJB 事务创建了许多新实体或以其它方式占用了许多 Bean,而这些 Bean 均使用 JDBC,WebLogic Server 就存在 oracle 游标数量不足的风险,因为 WebLogic Server 在尝试避免发生可疑的 oracle 驱动程序错误时会将对 JDBC 语句的关闭推迟到事务结束后进行,同时也将语句的游标一直保留到那个时候。WLS 6.1 SP7、WLS 7.0 SP5 和 WLS 8.1 SP3 中对此行为做了改动,会话已不必将游标一直保留到事务结束。
CR179600 - WLS 8.1 SP3 - 发生某些语句故障时,连接池的语句缓存会遗漏关闭语句的操作,进而导致 DBMS 会话中发生游标泄露。为解决此问题,已在 WLS 8.1 SP4 中做了改动。
CR174126 - 在单个事务中使用多个不同的预处理语句引发了 XA 语句缓存错误,缓存因此丢失了未关闭 JDBC 语句的句柄。这迅速导致 oracle 中所有可用的游标被消耗和泄漏。在 WLS 8.1 SP3 (English) 中对用于实现 XA 语句缓存的底层回收对象进行了修正。
CR188814 - WLS 8.1 SP2 - 使用 EJB 2.0 CMP 时,更新 BLOB 或 CLOB 列后未关闭 PreparedStatement 和 ResultSet。WebLogic Server 现在通过 WLS 8.1 SP4 实现了在更新 BLOB/CLOB 时关闭 PreparedStatement 和 ResultSet。
使用搜索功能也可以搜索到“Release Notes”,还可以搜索到其它支持解决办法及与 CR 有关的信息,如需要更多帮助?中所提到的内容。如果客户签订了技术支持合同,则可以登录 http://support.bea.com/,登录后会看到为 Solutions 和 Bug Central 提供的 Browse portlet,可在其中按产品版本浏览最新提供的 CR。
返回页首
需要更多帮助?
如果您已经理解这个模式,但仍需要更多帮助,您可以:
在 http://support.bea.com/ 上查询 AskBEA(例如,使用“ORA-01000: maximum open cursors exceeded”,以查找其它已发布的解决办法。技术支持合同客户:确保已经登录,可以访问提供的与 CR 有关的信息。
在 http://newsgroups.bea.com/ 上,向 BEA 的某个新闻组提出更详细具体的问题。
如果这还不能解决您的问题,并且您拥有有效的技术支持合同,您可以通过登录以下网站来打开支持案例:http://support.bea.com/。
反馈
请给我们提供您的意见,说明此支持诊断模式探查“ORA-01000:超出最多允许打开的游标数”一文是否有所帮助、您需要的任何解释,以及对支持诊断模式的新主题的任何要求。
分享到:
相关推荐
如果应用程序打开的游标数超过这个限制,会引发 ORA-01000: maximum open cursors exceeded 异常。下面将探讨超出打开游标的最大数的原因和解决方案。 原因 应用程序打开的游标数超过 OPEN_CURSORS 参数指定的最大...
### ora-01033: Oracle Initialization or Shutdown in Progress 解决方法 #### 一、问题背景及原因 **标题**: “ora-01033: Oracle initialization or shutdown in progress 解决方法” **描述**: “ora-01033: ...
### 如何处理错误ORA-29275:部分多字节字符 #### 问题背景与描述 在Oracle数据库操作过程中,用户可能会遇到一个特定的错误提示——ORA-29275:部分多字节字符。这一错误通常出现在执行查询`SELECT * FROM V$...
解决疑难问题,针对偏僻的问题:oracle超出打开游标的最大数的原因和解决方案,希望能对大家操作数据库有用处
ORA-00604: 递归SQL层1出现错误 ORA-03106: 致命的双工通信协议错误 ORA-02063: 紧接着line(源于dblink) 以及 ORA-04052: 在查找远程对象时出错 ORA-00604: 递归SQL层1出现错误 ORA-03120: 双工转换例行程序:整数...
ORA-00018: 超出最大会话数 ORA-00019: 超出最大会话许可数 ORA-00020: 超出最大进程数 () ORA-00021: 会话附属于其它某些进程;无法转换会话 ORA-00022: 无效的会话 ID;访问被拒绝 ORA-00023: 会话引用进程...
ORA-12154: TNS: 无法解析指定的连接标识符的解决方法
在Oracle数据库管理中,"ORA-00990: 权限缺失或无效"是一个常见的错误代码,它表示用户尝试执行的操作没有足够的权限。这个错误通常发生在试图访问、修改或者管理数据库对象(如表、视图、索引等)时。在本篇文章中...
ORA-32001:write to spfile requested but no spfile is in use请求写入spfile,但没有使用spfile的解决方法 在输入以下语句中报了这样的错误: SQL>alter system set control_files=’/u01/app/oracle/oradata/prod/...
#### ORA-00001: Unique Constraint Violated 当尝试插入或更新违反唯一约束的数据时触发此错误。例如,在具有唯一索引的列上插入重复数据。 #### ORA-00017: Rollback Segment Full 在进行事务回滚操作时,如果...
在Oracle数据库系统中,"ORA-00060: 等待资源时检测到死锁" 是一个常见的错误提示,它表明两个或多个事务在执行过程中陷入了无法继续进行的状态,因为彼此都在等待对方释放资源。这种情况通常发生在并发操作中,比如...
在Oracle数据库中,"ORA-00904"是一个常见的错误代码,它表示尝试引用一个不存在或无效的标识符。在这个场景下,错误信息提到的是"WM_CONCAT"函数,这表明在Oracle 19c数据库环境中,用户尝试使用WM_CONCAT函数,但...
在Oracle数据库系统中,"ORA-01036:非法的变量名/编号"是一个常见的错误,通常出现在PL/SQL代码或者SQL查询语句中,当你尝试使用一个不正确或者未定义的变量时,Oracle数据库会抛出这个错误。这个错误可能是由于...
oracle12c程序连接时异常: ORA-01017: 用户名/口令无效; 登录被拒绝 的解决方案。
ORA-00001: 违反唯一约束条件 (.) ORA-00017: 请求会话以设置跟踪事件 ORA-00018: 超出最大会话数 ORA-00019: 超出最大会话许可数 ORA-00020: 超出最大进程数 () ORA-00021: 会话附属于其它某些进程;无法转换会话 ...
在使用Oracle Data Pump工具IMPDP(Import Data Pump)进行数据导入的过程中,可能会遇到ORA-39002和ORA-39070等错误。本文将针对这些错误的排查方法进行详细介绍,帮助用户理解问题的原因及解决策略。 ### 错误...
然而,当你尝试向CLOB字段插入数据时,如果超过了Oracle规定的最大限制,就会遇到“ORA-01704: 文字字符串过长”的错误。这个错误通常意味着你试图插入的字符串超过了Oracle数据库允许的最大长度,对于VARCHAR2类型...
-- 解决ORA-00904: "WMSYS"."WM_CONCAT": 标识符无效 的文件包....... -- 解决ORA-00904: "WMSYS"."WM_CONCAT": 标识符无效 的文件包....... -- 解决ORA-00904: "WMSYS"."WM_CONCAT": 标识符无效 的文件包....... ...
* ORA-00018: 超出最大会话数 * ORA-00019: 超出最大会话许可数 * ORA-00020: 超出最大进程数 * ORA-00021: 会话附属于其它某些进程;无法转换会话 * ORA-00022: 无效的会话 ID;访问被拒绝 * ORA-00023: 会话引用...