我无法理解ORA-01722背后的原因:无效数字

时间:2012-05-17 12:53:31

标签: java oracle jdbc prepared-statement ora-01722

我有一个随机生成的问题(千分之一的呼叫之间)。 在预准备语句Oracle数据库中执行sql update时,会以随机方式生成错误 ORA-01722:无效数。案例详情如下:

try {
        connection = getConnection();
        statement = connection.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            if (params[i] instanceof Date) {
                statement.setTimestamp(i + 1, new Timestamp(((Date) params[i]).getTime()));
            } else if (params[i] instanceof java.util.Date) {
                statement.setTimestamp(i + 1, new Timestamp(((java.util.Date) params[i]).getTime()));
            } else {
                statement.setObject(i + 1, params[i]);
            }
            paramsBuilder.append(": " + params[i]);
        }
        if (logger.isInfoEnabled()) {
            logger.info("Query String  [" + sql + "] [" + paramsBuilder + "]");
            logger.info("Query Parameters [" + paramsBuilder + "]");
        }
        result = statement.executeUpdate();
        if (logger.isInfoEnabled()) {
            logger.info(result + " rows affected");
        }
    } catch (SQLException e) {
        if (logger.isInfoEnabled()) {
            String message = "Failed to execute SQL statment [" + sql + "] with parameters [" + paramsBuilder + "]";
            logger.error(message, e);
        }
        throw new DAOException(e);
    }

并且log中的值是这样的:

Failed to execute SQL statment [update CUSTOMER_CASE set no_of_ptp=?, no_of_unreached=?,collector_name=? , last_case_status_history_id=?, current_handler=?, handling_start_time=?,due_total_open_amount=?, payment_due_invoice_id =?  where id=?] with parameters [: 0: 0: auto: 5470508: null: null: 0.0: 23410984: 2476739] java.sql.SQLException: ORA-01722: invalid number

通过跟踪DB上的查询参数,所有参数都通过JDBC驱动程序正确传输,但参数 23410984 除外,它被值"<C4>^X* U"替换(注意此值包含char之前的回车符'你'!)。我不知道为什么

4 个答案:

答案 0 :(得分:5)

关键原因是java.sql.SQLException: ORA-01722: invalid number  可能是字段last_case_status_history_id类型是数字,但您的参数为空

答案 1 :(得分:3)

我们遇到了类似的问题。我们的基于hibernate的java代码发出了一个准备好的语句,用于通过使用aspectJ来填充所有保存操作的用户信息和“更改原因”。

在3个独立的数据库环境(Oracle 10G)中,这没有任何问题,但在生产数据库上,这有时会因ORA-01722错误而失败。仅当数据库服务器上的cpu负载接近100%时才会发生这种情况。

在另一个论坛上,我发现了一个关于不传递Long对象但是明确地将取消装箱传递给长基元的建议。看起来jdbc驱动程序或数据库本身在高负载下进行拆箱时会出现问题(即使这听起来很疯狂)。测试了各种jdbc驱动程序,例如1.4和1.6版本。

有时失败的代码是:

private void execute(final Long userId, final String rfc) {
    Object[] args = new Object[]{ userId, rfc };
    getJdbcTemplate().update("call schema.package.setUserAndRFC(?,?)", args);
}

现在我们更改了代码,使其成为一个明确的preparedStatement:

private void execute(final Long userId, final String rfc) {
    getJdbcTemplate().update(prepareStatement(userId.longValue(), rfc));
}

private PreparedStatementCreator prepareStatement(final long userId, final String rfc) {
    return new PreparedStatementCreator() {
        @Override
        public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
            PreparedStatement statement = con.prepareStatement("call schema.package.setUserAndRFC(?,?) ");
            statement.setLong(1, userId);
            statement.setString(2, rfc);
            return statement;
        }
    };
}

此问题从未发生过,即使环境在相同的软件和数据库上的高负载下保持不变。

我从一位同事那里听说,其中一位DBA可以在日志记录中看到准备好的语句已被数据库接受,但没有为其分配cpu。 (这是有道理的,因为所有的CPU都会在如此高的负载下忙碌。)可能只是抛出了错误的错误,应该抛出某些类型的“数据库重载”错误或其他东西。更好的是永远不会创造这样的错误。

我猜这主要是数据库负载,但是让cpu负载始终达到100%并不聪明。

答案 2 :(得分:2)

我试过了:

SELECT DUMP(23410984, 17)
FROM   dual;

得到了这个:

Typ=2 Len=5: c4,^X,*,^J,U

实际上与你得到的相同。类型2是NUMBER数据类型。

Oracle文档说明了DUMP()函数的第二个参数:

17返回作为字符打印的每个字节,当且仅当它可以被解释为编译器的字符集中的可打印字符 - 通常是ASCII或EBCDIC。某些ASCII控制字符也可以以^ X的形式打印。否则,字符以十六进制表示法打印。忽略所有NLS参数。

因此,似乎有时该值不是作为NUMBER的内部字节格式而是作为字符串传输。

答案 3 :(得分:0)

java.sql.SQLException: ORA-01722: invalid number

我在列的顶部使用了一个UDF,其中有一个数字,我得到的是一个不是数字的不同值。因此操作无法抛出无效数字异常。