调试ORA-01000

时间:2016-05-22 15:21:45

标签: oracle connection-pooling spring-jdbc oracle-aq ora-01000

我正在改变传统的Spring应用程序以利用动态配置的连接池。整个系统中的所有查询都使用JdbcTemplate,或者通过Jms连接到Oracle AQ - 我已经检查过,每次获取ResultSet时,它都会在finally {}块的框架代码中关闭。在我转移到动态配置的连接池之前,应用程序从未遇到任何麻烦。我目前正在使用C3P0作为我的连接池,但同样的问题也出现在使用DBCP2和Atomikos池中。问题在于:

经过一段时间的处理(似乎根据应用程序的行为而有所不同,但最终总是会发生)我的连接耗尽。出于绝望,我已经将连接数增加到10k,但这只会延长不可避免的时间。我运行这个查询:

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'
    and s.username = '<my app>' order by a.value asc ;

果然,

 VALUE USERNAME                              SID    SERIAL#
------ ------------------------------ ---------- ----------
     1 MY_APP                                 69      16665
     2 MY_APP                                149       9703
     3 MY_APP                                 13      38401
     4 MY_APP                                100       8629
     4 MY_APP                                145      26291
    29 MY_APP                                 49      30425
  2997 MY_APP                                147      33539
  5317 MY_APP                                 52      12599
  6425 MY_APP                                102      14803
 10000 MY_APP                                 19      18469

好的,我已经知道我的游标用完了。我知道我在网上看到的下一条建议是找出失控资源泄漏的原因,就是运行类似下面的查询:

select sql_text, sid, count(*) from v$open_cursor where user_name = '<my app>'
group by sql_text, sid having count(*) > 1 ;

我总共拿回了九排......这些家伙都没有超过三个。如果我删除&#34;有&#34;子句和总计所有游标计数,它相当于约120左右的游标。不是10k!

select sql_text, count(*) from v$open_cursor where sid = 19 group by sql_text having count(*) > 1 ;

SQL_TEXT                                                       COUNT(*)
--------------------------------------------------------     ----------
update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#         41

这是应用程序从一个插入语句中隐式获取一个新的序列值,该语句被JdbcTemplate正确地(也是隐式地)关闭。即便如此,41与10k的范围不同!

我知道v $ open_cursor表只代表&#34;缓存&#34;游标,以及某些游标计入&#34;打开游标当前&#34;统计数据可能已被标记为&#34;可关闭&#34;。有没有办法弄清楚这些打开的游标中涉及哪些确切的进程或sql?

我尝试了几种方法来试图弄清楚应用程序中发生了什么。我创建了一个特殊的数据源包装器,它将包装所有连接,语句,预处理语句,可调用语句及其生成的所有结果集,将它们保存在内存中的特殊集合中,并在关闭时将其删除。我以为我能够以这种方式捕获它 - 相反,通过这个池打开的每一个资源都被关闭了。最后一个。我甚至在连接池和spring引擎的内部调试,以观察Oracle thin ForwardOnlyResultSet被标记为已关闭。

我几乎可以怀疑问题出在与AQ的交互中,除了这个机制在旧版本的应用程序中运行良好。

我甚至尝试通过明确捕获ORA-01000错误并将其用作硬件重置连接池的触发器来解决此问题。只要它处理简单的任务,它就可以工作,但是对于某些正在进行数千次数据库操作的大型进程,在进程完成之前我就没有连接了;硬重置连接池使事务无效,整个事情进入无限循环。周围的情况很糟糕。

我完全不知所措......从应用程序方面来看,它看起来完全不透水,而从数据库方面看,我看起来并没有看到很多打开的游标v $ open_cursor,仅在统计中。不幸的是,统计数据似乎很重要。

帮助?

1 个答案:

答案 0 :(得分:1)

您的第一个SQL显示会话19有10,000个打开游标,而您的第3个SQL显示其中只有一个共享。结论,第19节有近10,000个独特的开放游标。通常的原因是使用不可共享的SQL。即,您没有在代码中使用任何绑定变量。这意味着每次您的应用程序运行SQL语句时,数据库都会为该语句打开一个新游标。当你的应用程序运行10000个语句时,你就会碰壁。

要解决此问题,可以设置数据库参数CURSOR_SHARING = FORCE。这将导致数据库自动将绑定变量替换为SQL中的文字,从而使您的SQL语句可共享。然后,每次应用程序运行SQL语句时,您都不会打开单独的游标。

以下是关于CURSOR_SHARING = FORCE的简短文章:http://www.dba-oracle.com/t_cursor_sharing_force.htm

如果您使用的是Oracle 9i或更高版本,则可以使用CURSOR_SHARING = SIMILAR。 (尽管有些DBA建议在Oracle 11或更高版本之前不使用SIMILAR,因为错误)

设置CURSOR_SHARING应该被视为快速解决方案,而不是最终解决方案。从长远来看,您应该重写您的应用程序,以便它使用绑定变量而不是使用CURSOR_SHARING来补偿。以下是对原因的一个很好的解释: https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:5180609822543

最后 - 设置CURSOR_SHARING应谨慎使用,并注意您可能无法获得预期的优化计划。