JDBC超时不会抛出SQLTimeoutException

时间:2014-09-30 22:04:40

标签: jdbc spring-jdbc

我正在尝试在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)

2 个答案:

答案 0 :(得分:2)

这是驱动程序用来抛出异常/错误的代码,它没有做任何事情来将异常映射到SQLTimeoutException。这是oracle驱动程序实现中的差距

https://github.com/wenshao/OracleDriver10_2_0_2/blob/4af5a9295e0e9fef3f7e51ba7bf735fb81e9186a/src/oracle/jdbc/driver/T4CTTIoer.java

从以下完整方法获取的片段是

     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

这有两个含义:

  1. 旧版本不提供
  2. 您需要一个适用于JDBC 4或更高版本的驱动程序。
  3. 还有其他并发症:

    1. 在您的问题中给出特定错误消息(“ORA-01013:用户请求取消当前操作”),驱动程序可能根本无法识别实际用户启动取消超时发起的声明。在这种情况下,最好抛出最通用的异常类型。

    2. 如果供应商支持多个Java和JDBC版本,他们可能只是采用快捷方式,只做最小的(几乎)符合JDBC。这可能只包括抛出SQLException,以便他们更容易使用相同的代码库,而且操作起来很少。