我有一个随机生成的问题(千分之一的呼叫之间)。 在预准备语句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之前的回车符'你'!)。我不知道为什么
答案 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,其中有一个数字,我得到的是一个不是数字的不同值。因此操作无法抛出无效数字异常。