ランダムに生成される問題があります(1000分の1の呼び出しの間に1回)。エラーORA-01722:無効な番号は、プリペアドステートメントのOracleデータベースでSQL更新を実行しているときにランダムに生成されます。ケースの詳細は以下のとおりです。
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 'の前のキャリッジリターンが含まれていることに注意してください) !)。理由はわかりません
主な理由はJava.sql.SQLException: ORA-01722: invalid number
についてです。
フィールドlast_case_status_history_id
タイプは数値である可能性がありますが、パラメータはnullです
同様の問題がありました。休止状態ベースのJavaコードは、aspectJを使用して、すべての保存操作のユーザー情報と「変更の理由」を入力するためのプリペアドステートメントを発行しました。
3つの別々のデータベース環境(Oracle 10G)では、これは問題なく機能しましたが、本番データベースでは、ORA-01722エラーで失敗することがありました。これは、データベースサーバーのCPU負荷が100%に近い場合にのみ発生します。
別のフォーラムで、Longオブジェクトを渡すのではなく、longプリミティブに対して明示的にボックス化解除を行うことについての提案を見つけました。高負荷でこのボックス化解除を行うと、jdbcドライバーまたはデータベース自体に問題があるようです(かなりおかしなことに聞こえますが)。 1.4および1.6バージョンなど、さまざまなjdbcドライバーがテストされました。
時々失敗したコードは次のとおりです。
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の1人が、準備されたステートメントがデータベースによって受け入れられたが、CPUが割り当てられていないことをログで確認できると聞きました。 (すべてのCPUがこのような高負荷でビジーになるため、意味があります。)単に間違ったエラーがスローされたり、ある種の「データベース過負荷」エラーがスローされたりする可能性があります。とにかくそのようなエラーを決して作成しないことはさらに良いでしょう。
それは主にデータベースの負荷だと思いますが、CPUの負荷を常に100%に到達させるのは賢明ではありません。
私はこれを試しました:
_SELECT DUMP(23410984, 17)
FROM dual;
_
そしてこれを手に入れました:
_Typ=2 Len=5: c4,^X,*,^J,U
_
これはあなたが得たものと実質的に同じです。タイプ2はNUMBER
データ型です。
Oracleのドキュメントには、DUMP()
関数の2番目のパラメータが記載されています。
17は、コンパイラの文字セットで印刷可能な文字として解釈できる場合にのみ、文字として出力される各バイトを返します。通常はASCIIまたはEBCDIC。一部ASCII制御文字は^ Xの形式でも出力できます。それ以外の場合、文字は16進表記で出力されます。すべてのNLSパラメーターは無視されます。
そのため、値がNUMBERの内部バイト形式ではなく、文字列として転送されることがあるようです。
Java.sql.SQLException: ORA-01722: invalid number
。
数値が予想される列の上でUDFを使用していましたが、数値ではない別の値を取得していました。したがって、操作は無効な番号例外をスローして失敗します。