我正在尝试在JDBC语句上设置查询超时,并期望它在超时时抛出SQLTimeoutException。 但相反,我得到一个通用的SQLException错误代码ORA-01013。
知道我必须缺少什么吗?
我正在寻找一种独立于数据库的方法来处理超时。检查数据库特定的错误代码可能无济于事。
顺便说一下,我是通过Spring的JdbcTemplate设置这个属性的。
myStatement.setQueryTimeout(1);
引发
java.sql.SQLException: ORA-01013: user requested cancel of current operation
编辑:这是错误的堆栈跟踪。我使用的是瘦驱动程序(ojdbc6-11.2.0.1.0.jar)。
java.sql.SQLException: ORA-01013: user requested cancel of current operation
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:861)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1145)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1259)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3493)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1491)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:703)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:644)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:722)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:772)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:211)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:219)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:233)
at mytest.MyDAO.retrieve(MyDAO.java:12)
答案 0 :(得分:2)
这是驱动程序用来抛出异常/错误的代码,它没有做任何事情来将异常映射到SQLTimeoutException。这是oracle驱动程序实现中的差距
从以下完整方法获取的片段是
DatabaseError.throwSqlException(this.meg.conv
.CharBytesToString(this.errorMsg, this.errorLength[0],
true), DatabaseError
.ErrorToSQLState(this.retCode), this.retCode);
完整的方法就是这个
/* */
/* */void processError(boolean paramBoolean,
OracleStatement paramOracleStatement)
/* */throws SQLException
/* */{
/* 303 */if (this.retCode != 0)
/* */{
/* 311 */switch (this.retCode)
/* */{
/* */case 28:
/* */
case 600:
/* */
case 1012:
/* */
case 3113:
/* */
case 3114:
/* 323 */this.connection.internalClose();
/* */}
/* */
/* 328 */if (paramBoolean)
/* */{
**/* 331 */
*DatabaseError.throwSqlException(this.meg.conv
.CharBytesToString(this.errorMsg, this.errorLength[0],
true), DatabaseError
.ErrorToSQLState(this.retCode), this.retCode);*
/* */}
/* */else
/* */{
/* 335 */return;
/* */}
/* */
/* */}
/* */
/* 341 */if (!paramBoolean) {
/* 342 */return;
/* */}
/* */
/* 351 */if ((this.warningFlag & 0x1) == 1)
/* */{
/* 353 */int i = this.warningFlag & 0xFFFFFFFE;
/* */
/* 356 */if (((i & 0x20) == 32) || ((i & 0x4) == 4)) {
/* 357 */throw DatabaseError.newSqlException(110);
/* */}
/* */}
/* */
/* 361 */if ((this.connection != null)
&& (this.connection.plsqlCompilerWarnings))
/* */{
/* 363 */if ((this.flags & 0x4) == 4)
/* 364 */paramOracleStatement.foundPlsqlCompilerWarning();
/* */}
/* */}
答案 1 :(得分:2)
不幸的是,JDBC驱动程序并不总是实现JDBC所需的一切(或:建议)。特别适用于'较新'的功能。 Java 6 / JDBC 4中添加了SQLTimeoutException
。
这有两个含义:
还有其他并发症:
在您的问题中给出特定错误消息(“ORA-01013:用户请求取消当前操作”),驱动程序可能根本无法识别实际用户启动取消超时发起的声明。在这种情况下,最好抛出最通用的异常类型。
如果供应商支持多个Java和JDBC版本,他们可能只是采用快捷方式,只做最小的(几乎)符合JDBC。这可能只包括抛出SQLException
,以便他们更容易使用相同的代码库,而且操作起来很少。