【问题标题】:I can't understand the reason behind ORA-01722: invalid number我无法理解 ORA-01722 背后的原因:无效号码
【发布时间】:2012-05-17 12:53:30
【问题描述】:

我有一个随机生成的问题(在千分之一的调用之间出现一次)。 错误 ORA-01722: invalid number 是在准备好的语句 Oracle 数据库中执行 sql update 时随机生成的。案例详情如下:

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);
    }

日志中的值是这样的:

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 'u 之前包含回车' !)。不知道为什么

【问题讨论】:

  • 您要插入的对象的类型是什么? toString() 返回 23410984,但它是 Integer、Long 还是 BigDecimal?
  • statementresult的范围是什么?
  • 对象类型为long,数据库列为number
  • 我在使用 IN() 子句删除时遇到了同样的问题。执行子查询并避免将字符串值放入查询中可以避免此问题
  • 当我们使用 IN 子句并将值作为 IN ('1, 2, 3, 4, ...') 传递时,通常会发生这种情况,值应按以下方式传递 IN ('1 ','2','3','4',...)

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


【解决方案1】:

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

【讨论】:

  • 当我们使用 IN 子句并将值作为 IN ('1, 2, 3, 4') 传递而不是按照以下方式传递时会发生这种情况 IN ('1','2 ','3','4')
【解决方案2】:

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

在 3 个独立的数据库环境 (Oracle 10G) 中,这可以正常工作,但在生产数据库中,这有时会失败,并出现 ORA-01722 错误。这只发生在数据库服务器上的 cpu 负载接近 100% 时。

在另一个论坛上,我发现了一个关于不传递 Long 对象而是明确对 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% 一点也不聪明。

【讨论】:

  • 通常这种情况发生在我们使用 IN 子句并将值作为 IN ('1, 2, 3, 4') 传递而不是按照以下方式传递时 IN ('1','2' ,'3','4')
【解决方案3】:

我试过了:

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 的内部字节格式而是作为字符串传输的。

【讨论】:

  • 也许您应该对非时间戳值更明确,并使用setLong()
【解决方案4】:

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

我在需要数字的列顶部使用 UDF,而我得到的不是数字的不同值。所以操作失败,抛出无效数字异常。

【讨论】:

    【解决方案5】:

    当我们使用 IN 子句并将值传递为 IN ('1, 2, 3, 4') 而不是按照下面的方式传递 IN ('1','2','3','4')

    【讨论】:

      猜你喜欢
      • 2019-08-09
      • 2023-03-15
      • 2020-05-09
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 2018-02-14
      相关资源
      最近更新 更多