0

我有一套 JUnit 测试,可以在 STS/Eclipse 用完时工作,但在使用 Jacoco 从 Bamboo 运行时不起作用。当我们使用 Cobertura 从 Jenkins 运行测试时,它曾经工作过。当我说工作时,我的意思是测试出错了,特别是涉及我们的 SQL 数据库 (Oracle) 的测试。不接触数据库的测试没有错误。我们现在也使用比以前更好/更快的硬件,所以可能就是这样。我们现在也在运行 Java 8 而不是 7。但就像我说的,测试在 STS/Eclipse 上运行良好。我们一次改变了很多东西,所以我不知道该怎么做。

该错误具体是“错误发生在递归 SQL 级别 1 ORA-01000 超出最大打开游标”。

我们使用 Springsource Framework、ojdbc6 和 ucp,错误发生在以下堆栈跟踪中:

    org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; SQL [] 的未分类 SQLException;SQL状态[60000];错误代码[604];ORA-00604: 递归 SQL 级别 1 发生错误 ORA-01000: 超出最大打开游标;嵌套异常是 java.sql.SQLException: ORA-00604: 递归 SLQ 级别 1 发生错误 ORA-01000: 超出最大打开游标
    在
    org.springframework.jdbc.support.AbstractFallbackSLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
    在
    org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
    在
    org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
    在
    org.springframework.jdbc.core.JdbcTemplate.execute (JdbcTemplate.java:660)
    在
    mycompany.db.StatementManager.execute(StatementManager.java:183)
    在
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    在
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    在
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    在
    org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    在
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    在
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    在
    com.sun.proxy.$Proxy27.execute(未知来源)
    在
    mycompany.db.SomeDbCode.clear(SomeDbCode.java:48)
    在
    ........更多无关的AOP层......
    mycompany.db.TestSomeDb.setup(TestSomeDb.java:115) //这在每组单元测试之前运行,以使用 @Before 将表截断为原始状态
    在
    .....分层到跑步者......
    在
    org.springframework.test.context.junit4.SpringJUnit4ClassRnner.run (SpringJUnit4ClassRunner.java:163)
    原因:java.sql.SQLException:ORA-00604:递归 SQL 级别 1 发生错误
    ORA-01000: 超出最大打开游标
    在
    oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
    在
    oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
    在
    oracle.jdbc.driver.T4C80all.processError(T4C80all.java:802)
    在
    oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
    在
    oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
    在
    oracle.jdbc.driver.T4C80all.do0ALL(T4C80all.java:521)
    在
    oracle.jdbc.driver.T4CPreparedStatement.do0all8(T4CPreparedStatement.java:205)
    在
    oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1008)
    在
    oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
    在
    oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)
    在
    oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3530)
    在
    oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
    在
    oracle.ucp.jdbc.proxy.StatementProxyFactory.invoke(StatementProxyFactory.java:230)
    在
    oracle.ucp.jdbc.proxy.StatementProxyFactory.invoke(StatementProxyFactory.java:124)
    在
    com.sun.proxy.$Proxy113.executeUpdate(未知来源)
    在
    mycompany.db.StatementManager$ExecuteFiller.doInPreparedStatment(StatementManager.java:44)
    在
    org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:644)

顺便说一句,这一切都来自于尝试调用:

TRUNCATE TABLE 某个表名

我想我已经找到了根本原因,尽管还不是解决它的最佳方法(对想法开放)。

每组测试都会打开一些游标。随着那组测试完成运行,Spring 开始清理游标。但随后下一类测试开始并开始打开新的游标。我正在通过运行查询How to find Current open Cursors in Oracle 来观察“打开的游标”数字是否呈正弦增长 。显然我的旧硬件太慢了,清理速度比增长速度快,但是有了新硬件,它最终达到了 300 的限制(所以在某些时候团队中的其他人意识到默认的 50 太少了,当然有没有关于如何确定 300 正确的文档),以及该错误之后的任何测试都出现了该错误。

我试图缓解的事情:为所有涉及数据库的测试提供一个名为 TouchesDatabase 的超类,并使用一个休眠 10 秒的 @AfterClass 方法。
这实际上修复了除我的一个测试之外的所有测试,但它也使构建花费了两倍的时间来构建。

所以我想,好吧,显然有些测试打开的游标比其他测试多,所以我不会做 10 秒,而是查询打开了多少游标,如果超过 100,我会再睡一秒钟。不幸的是,我正在使用的游标查询(可能必须尝试不同的查询)似乎是多算了一些事情,或者做了一些奇怪的事情,因为下降到 100 个游标以下似乎需要更长的时间,而不是仅仅 10 秒的睡眠。当我不得不离开一天时,它就像第 3 次或第 4 次 db 测试课(超过 30 分钟)并且已经运行了 30 分钟,所以我会在早上看看,但显然不理想。

如果我找不到更好的游标查询,那么我将开始检查每个测试,看看是否有更聪明的方法可以在那里做事。顺便说一句,我们对生产应用程序没有任何问题,只是测试。

4

0 回答 0