Spring Boot Application using Oracle – ORA-01000: maximum open cursors exceeded – error happening during load testing

huangapple go评论93阅读模式
英文:

Spring Boot Application using Oracle - ORA-01000: maximum open cursors exceeded - error happening during load testing

问题

正在开发一个 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 数据库游标限制为 1000。
负载测试运行了 1 小时 55 分钟后出现了错误,我们的服务失败率为 0.5%,
用户/线程数量设置为 25。

寻找一些建议来解决这个问题。

英文:

Am working on spring-boot application. While performing load testing we get error

"ORA-01000:maximum open cursors exceeded"

We have following entries for spring boot and jdbc in the pom.xml file

&lt;parent&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
    &lt;version&gt;2.1.6.RELEASE&lt;/version&gt;
&lt;/parent&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-jdbc&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;com.oracle&lt;/groupId&gt;
    &lt;artifactId&gt;ojdbc6&lt;/artifactId&gt;
    &lt;version&gt;11.2.0.3&lt;/version&gt;
&lt;/dependency&gt;

To fix the issue I tried changing the "ojdbc" from 6 to 8.

&lt;dependency&gt;
    &lt;groupId&gt;com.oracle.jdbc&lt;/groupId&gt;
    &lt;artifactId&gt;ojdbc8&lt;/artifactId&gt;
    &lt;version&gt;12.2.0.1&lt;/version&gt;
&lt;/dependency&gt;

but I still got the same issue.

All our backend calls using either "jdbcTemplate" or "namedParameterJdbcTemplate".

The error is happening during load testing.
Our Oracle DB cursor limit is 1000.
Load test run game the error after 1hr 55mins and failure rate our our service was 0.5%
the number of users/threads is set to 25.

Looking for some suggestions to fix this issue.

答案1

得分: 1

我的第一个建议是将Spring库,包括Spring JDBC和JPA版本,升级到最新版本。之前的Spring JPA版本没有正确关闭游标。

这个问题通常是由于没有清理resultsetsstatements或连接所导致的。每个创建的ResultSet在后端使用一个游标。如果你从不关闭ResultSet,创建它的Statement或用于该语句的Connection,这些游标就不会关闭。由于你在使用连接池,连接从物理上不会关闭,因此游标也永远不会关闭。

在JDBC Java中,是什么导致了"ora-01000 maximum open cursors exceeded java.sql.SQLException"问题呢?

  1. 不关闭JDBC的Statement对象会导致最大打开游标超过java.sql.SQLException,
  2. 不关闭JDBC的PreparedStatement对象会导致最大打开游标超过java.sql.SQLException,
  3. 不关闭JDBC的CallableStatement对象会导致最大打开游标超过java.sql.SQLException,
  4. 不关闭JDBC的ResultSet对象以及不关闭JDBC的Connections对象会导致最大打开游标超过java.sql.SQLException。

Spring的JdbcTemplate是否关闭连接?并非总是如此。

合格的开发者通常知道他们必须在try/catch/finally中清理连接、文件句柄或任何其他数量的事情。但是对于Java来说,你会听到"只需使用JdbcTemplate!它会为你处理所有这些样板代码!"。我很久以来一直认为JdbcTemplate除了关闭结果集外,还会清理连接。实际上,在网上你会经常看到这种说法。但要小心!这似乎并不是情况,或者如果是的话,至少是数据源相关的...如果你考虑它们的目的,这实际上是有道理的。

当你没有一个由Spring管理的事务时,JdbcTemplate会调用连接上的close()方法。然而,如果已经有一个连接可用,由于Spring的事务管理关闭连接将由Spring的事务支持处理,而这反过来也会在连接上调用close()

编辑:

解决方法:

通过在数据库上执行以下SQL命令来增加数据库中的最大打开游标数:

ALTER SYSTEM SET open_cursors = 1000 SCOPE=BOTH;

此示例将最大打开游标数设置为1000。根据需要更改此值。

解决方案:

将Oracle JDBC驱动程序更新到最新版本(12.2.0.1)

有一个新版本的Oracle JDBC驱动程序修复了游标泄漏问题。

英文:

My first suggestion would be to upgrade the update Spring Library including Spring JDBC and JPA version to latest. The earlier spring JPA version was not closing the cursors properly.

This problem occurs commonly because of not cleaning up resultsets, statements or connections. Each ResultSet that you create, uses a cursor on the backend. If you never close the ResultSet, the Statement that created it or the Connection that was used for the statement, those cursors never get closed. As you are using a connection pool, the connections are never physically closed, thus the cursors are never closed either.

What causes the Solve ora-01000 maximum open cursors exceeded java.sql.SQLException problem in JDBC java-

  1. Not closing the JDBC Statement object can cause maximum open cursors
    exceeded java.sql.SQLException,
  2. Not closing the JDBC PreparedStatement object can cause maximum open
    cursors exceeded java.sql.SQLException,
  3. Not closing the JDBC CallableStatement object can cause maximum open
    cursors exceeded java.sql.SQLException,
  4. Not closing the JDBC ResultSet object and Not closing the JDBC
    Connections object can cause maximum open cursors exceeded
    java.sql.SQLException

Does Spring JdbcTemplate Close Connections? … Not Always.

Decent developers usually know that they have to try/catch/finally to ensure they clean up connections, file handles, or any number of things. But then, for Java, you hear “just use JdbcTemplate! it does all this boilerplate for you!”. I had, for the longest time, assumed that JdbcTemplate would clean up connections in addition to results sets. In fact, you’ll see this online a lot. But be careful! This does not appear to be the case, or if it is, it is at least data source dependent… and that actually makes sense if you think about their purpose.

When you don't have a Spring managed transaction then yes the JdbcTemplate will call the close() method on the Connection. However if there was already a connection available due to Springs transaction management closing the connection will be handled by Springs transaction support, which in turn also will call close() on the Connection.

EDIT:

Workaround:

Increase the maximum open cursor in the database by executing the following SQL command on the database:

ALTER SYSTEM SET open_cursors = 1000 SCOPE=BOTH;

This example sets the maximum open cursors to 1000. Change this value as required.

Resolution:

Update the Oracle JDBC Driver to the latest version (12.2.0.1)

There is a new version of the Oracle JDBC driver which fixes the cursor leak.

答案2

得分: 1

好的,以下是翻译好的部分:

我终于得到了一个答案。我的项目与你的完全相同(Spring Boot 2.1.6.RELEASE 和 ojdbc8 12.2.0.1),(此外还使用了 Spring Data JPA,)但将版本升级到 2.2.5.RELEASE 对我没有起作用。

每次我使用一定数量的数据(或更多)调用相同函数时,都会出现相同的异常。我试图通过升级 ojdbc 版本到 19.6.0.0,添加 Spring 配置 spring.jdbc.getParameterType.ignore 等方法来摆脱这个错误,但是这些方法对我都没有起作用。

最终,我发现了 JPA 存储库方法的返回类型。最初我的方法是这样的:

Stream<MyEntity> findByMyColumn(MyColumnType myColumnValue);

请注意,这个存储库方法的返回类型是 java.util.Stream。我之所以将返回类型设置为流是因为只有在需要流式处理时才会使用这个方法。
并且每次我执行相同的过程时,堆栈跟踪中都包含这个方法,我感到很奇怪。
所以我将类型更改为 List,错误就消失了!!!

List<MyEntity> findByMyColumn(MyColumnType myColumnValue);

我认为即使流已经结束,Stream 仍然会保持游标。显然,这是 Spring Boot 或 ojdbc 的一个 bug,但是它们似乎都没有意识到或愿意修复这个问题。

希望这对你的情况也有所帮助。

英文:

Okay, I finally got an answer. My project was EXACTLY same as yours(Spring boot 2.1.6.RELEASE and ojdbc8 12.2.0.1), (additionally Spring data jpa,) and upgrading version to 2.2.5.RELEASE didn't work for me.

I had the same exception occurs when every time I call the same function using certain amount of data(or above) - I tried to get rid of this error by upgrading ojdbc version to 19.6.0.0, adding spring config spring.jdbc.getParameterType.ignore, and so on. None of them works for me.

Finally what I found was the return type of jpa repository method. Originally my method was like this :

Stream&lt;MyEntity&gt; findByMyColumn(MyColumnType myColumnValue);

note that the return type of this repository method is java.util.Stream. The reason why I get this return type as stream is that this method is used only when the streaming is required.
And everytime I execute same procedure, the stack trace contains this method and I feel weird.
So I changed the type to List, and the error is GONE!!!

List&lt;MyEntity&gt; findByMyColumn(MyColumnType myColumnValue);

I think that the Stream is holding cursors even if the stream ended. Obviously it's a bug on Spring boot or ojdbc, but none of them seems to recognize or have willing to fix this problem.

Hope that helps to your situation, too.

答案3

得分: 0

好的,以下是翻译好的部分:

"ok, this took long for me to come back and post.
So for me this issue got resolbved just by having following entry in pom.xml

<dependency>
        <groupId>com.oracle.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>12.2.0.1</version>
    </dependency>

and for sometime when it didnt work we realized there was another ojdbc7 which was getting picked up by the environment and it was getting introduced due to some other dependency. So once we suppressed that the ojdbc8 got picked up and our issue got resolved."

英文:

ok, this took long for me to come back and post.
So for me this issue got resolbved just by having following entry in pom.xml

&lt;dependency&gt;
    &lt;groupId&gt;com.oracle.jdbc&lt;/groupId&gt;
    &lt;artifactId&gt;ojdbc8&lt;/artifactId&gt;
    &lt;version&gt;12.2.0.1&lt;/version&gt;
&lt;/dependency&gt;

and for sometime when it didnt work we realized there was another ojdbc7 which was getting picked up by the environment and it was getting introduced due to some other dependency. So once we suppressed that the ojdbc8 got picked up and our issue got resolved.

答案4

得分: 0

升级到最新的Oracle JDBC驱动程序解决了这个问题。我们升级到了版本:12.2.0.1。

英文:

Upgrading to the latest oracle jdbc driver solved the problem. We upgraded to : version (12.2.0.1)

huangapple
  • 本文由 发表于 2020年4月7日 08:58:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/61071201.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定