使用 Oracle 的 Spring Boot 应用程序 - ORA-01000:超出最大打开游标 - 负载测试期间发生错误
Posted
技术标签:
【中文标题】使用 Oracle 的 Spring Boot 应用程序 - ORA-01000:超出最大打开游标 - 负载测试期间发生错误【英文标题】:Spring Boot Application using Oracle - ORA-01000: maximum open cursors exceeded - error happening during load testing 【发布时间】:2020-04-07 00:58:05 【问题描述】:我正在开发 spring-boot 应用程序。在执行负载测试时出现错误
"ORA-01000: 超出最大打开游标"
我们在 pom.xml 文件中有以下关于 spring boot 和 jdbc 的条目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
为了解决这个问题,我尝试将“ojdbc”从 6 更改为 8。
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
</dependency>
但我仍然遇到同样的问题。
我们所有的后端调用都使用“jdbcTemplate”或“namedParameterJdbcTemplate”。
在负载测试期间发生错误。 我们的 Oracle DB 游标限制为 1000。 负载测试运行游戏 1 小时 55 分钟后出现错误,我们的服务失败率为 0.5% 用户/线程数设置为 25。
寻找一些建议来解决这个问题。
【问题讨论】:
***.com/q/12192592/7505731 将为您提供有关此异常的见解 感谢分享,虽然大部分内容是指关闭连接结果集等。但是在我的代码中,我们使用 jdbctemplate 或 namedParameterJdbcTemplate 并直接获取数据,因此没有参考结果或连接等。 【参考方案1】:我的第一个建议是将包括 Spring JDBC 和 JPA 版本的更新 Spring 库升级到最新版本。较早的 Spring JPA 版本没有正确关闭游标。
这个问题通常是因为没有清理resultsets
,语句或连接。您创建的每个 ResultSet 都在后端使用一个游标。如果您从不关闭 ResultSet、创建它的 Statement 或用于该语句的 Connection,则这些游标永远不会关闭。当您使用连接池时,连接永远不会物理关闭,因此游标也永远不会关闭。
是什么导致了 JDBC java 中的 Solve ora-01000 maximum open cursors exceeded java.sql.SQLException
问题-
-
不关闭 JDBC
Statement
对象会导致最大打开游标
超出 java.sql.SQLException,
不关闭 JDBC PreparedStatement
对象会导致最大打开
游标超出 java.sql.SQLException,
不关闭 JDBC CallableStatement
对象会导致最大打开
游标超出 java.sql.SQLException,
未关闭 JDBC ResultSet
对象且未关闭 JDBC
Connections 对象可能导致超出最大打开游标
java.sql.SQLException
Spring JdbcTemplate 是否关闭连接? … 并非总是如此。
体面的开发人员通常知道他们必须尝试/捕获/最终以确保他们清理连接、文件句柄或任何数量的东西。但是,对于 Java,您会听到“只需使用 JdbcTemplate
!它为你做了所有这些样板!”。很长一段时间以来,我一直认为JdbcTemplate
会清理除结果集之外的连接。事实上,你会在网上看到很多。不过要小心!情况似乎并非如此,或者如果是的话,它至少取决于数据源……如果您考虑它们的目的,这实际上是有道理的。
当您没有 Spring 托管事务时,是的,JdbcTemplate
将在 Connection 上调用 close()
方法。但是,如果由于 Springs 事务管理关闭而已经有可用的连接,则该连接将由 Springs 事务支持处理,而后者也会在 Connection 上调用 close()
。
编辑:
解决方法:
通过对数据库执行以下 SQL 命令来增加数据库中的最大打开游标:
ALTER SYSTEM SET open_cursors = 1000 SCOPE=BOTH;
此示例将最大打开游标设置为 1000。根据需要更改此值。
分辨率:
将 Oracle JDBC 驱动程序更新到最新版本 (12.2.0.1)
有一个新版本的 Oracle JDBC 驱动程序修复了游标泄漏。
【讨论】:
感谢您的回答,但我没有对结果集、语句或连接进行任何引用。在我的 DAO 实现中,我只是调用 jdbctemplate 或 namedparameterjdbctemplate 并进行诸如 queryForObject 等方法调用。所以我不确定即使我添加 try catch,因为我不持有对结果等的引用,然后我会关闭什么。 另外,我还没有实现任何连接池。 @pooja 你的交易管理怎么样?就像创建、打开和关闭连接一样。是由 Spring JDBC Transaction 管理的,例如:数据库事务管理器。您是否使用了任何注释,例如 EnableTransactionManagement 或 Transactional。 所以在一些进行 Dao 调用的方法上,我看到我们有 @Transactional 但不是在所有方法上。而且我还知道我们在部署此应用程序的 tomcat 服务器级别维护了连接池。 我们还尝试通过在 pom.xml 中添加以下内容来实现连接池好的,我终于得到了答案。我的项目与您的项目完全相同(Spring boot 2.1.6.RELEASE 和 ojdbc8 12.2.0.1),(另外还有 Spring data jpa),并且将版本升级到 2.2.5.RELEASE 对我不起作用。
每次我使用一定数量的数据(或以上)调用相同的函数时都会发生相同的异常 - 我试图通过将 ojdbc 版本升级到 19.6.0.0 来消除此错误,添加 spring config spring.jdbc .getParameterType.ignore 等等。它们都不适合我。
最后我发现的是 jpa 存储库方法的返回类型。原来我的方法是这样的:
Stream<MyEntity> findByMyColumn(MyColumnType myColumnValue);
请注意,此存储库方法的返回类型是 java.util.Stream。我之所以将此返回类型设为流,是因为仅在需要流式传输时才使用此方法。 每次我执行相同的程序时,堆栈跟踪都包含这个方法,我觉得很奇怪。 于是我把类型改成了List,报错GONE了!!!
List<MyEntity> findByMyColumn(MyColumnType myColumnValue);
我认为即使流结束,流也会保留游标。显然这是 Spring boot 或 ojdbc 上的一个 bug,但他们似乎都没有意识到或愿意修复这个问题。
希望对您的情况也有帮助。
【讨论】:
使用后必须关闭流:docs.spring.io/spring-data/jpa/docs/current/reference/html/…【参考方案3】:好的,我花了很长时间才回来发帖。 所以对我来说,这个问题只需在 pom.xml 中添加以下条目即可解决
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
</dependency>
当它不起作用时,我们意识到有另一个 ojdbc7 被环境拾取,并且由于其他一些依赖性而被引入。因此,一旦我们抑制了 ojdbc8 被拾取,我们的问题就得到了解决。
【讨论】:
【参考方案4】:升级到最新的 oracle jdbc 驱动程序解决了这个问题。我们升级到:版本(12.2.0.1)
【讨论】:
以上是关于使用 Oracle 的 Spring Boot 应用程序 - ORA-01000:超出最大打开游标 - 负载测试期间发生错误的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 TestContainers + Spring Boot + oracle-xe
JobStoreTX 的 Spring boot + Quartz + Oracle 问题
Spring boot + oracle 驱动 + 没有合适的驱动