使用 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 中添加以下内容来实现连接池 org.springframework.bootspring-boot-starter-data-jpa 2.2.4.RELEASE 和 application.properties 中的必需条目,但它仍然给出错误【参考方案2】:

好的,我终于得到了答案。我的项目与您的项目完全相同(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:超出最大打开游标 - 负载测试期间发生错误的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 从 Oracle 配置入手

如何使用 TestContainers + Spring Boot + oracle-xe

JobStoreTX 的 Spring boot + Quartz + Oracle 问题

Spring boot + oracle 驱动 + 没有合适的驱动

使用 Spring Boot 的 Oracle 到 SQL Server 数据传输

Spring boot Oracle JPA 设置 QueryTimeout