5

我对 Dbutils 有一个奇怪的问题,我正在尝试运行参数化更新 sql,我提供了正确数量的参数,但是 dbutils 正在通过更改修改它的名称来修改时间戳列名称

当时间戳列名是一个字母时

java.sql.SQLException:错误数量的参数:预期 4,给出了 5 查询:UPDATE WEATHER_2 SET WEATHER=? , O=TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF') , 湿度=? , 温度=? 在哪里 ID =?参数:[804, 2015-06-05 17:21:05.809, 16.0, 25.15, 1347927]

当时间戳列名正常时..它将省略第二个字母

java.sql.SQLException:ORA-00904:“OSTIME”:无效标识符查询:UPDATE WEATHER_2 SET WEATHER=? , OBSTIME=TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF') , 湿度=? , 温度=? 在哪里 ID =?参数:[804, 2015-06-05 17:27:46.139, 16.0, 25.15, 1347927]

这可能是数据库的事情吗?此外,这仅发生在类型为日期或时间戳的列上。

4

3 回答 3

7

我有一个类似的问题。我认为这是 Oracle JDBC 7 驱动程序 (ojdbc7.jar) 中的错误。该错误可能在 PreparedStatement.getParameterMetaData 方法中。

此方法由 Apache DBUtils 在内部使用。所以这不是 DBUtils 的错误,而是 Oracle JDBC 驱动程序与 Oracle 12c 一起分发的错误。

如果您使用 Oracle 11g ojdbc6.jar 驱动程序,相同的查询可能会正常工作。它至少对我有用。

如果要查看Oracle ojdbc7.jar 驱动程序内部如何错误处理Query,可以使用oracle.jdbc.driver.OracleParameterMetaDataParser 类中包含的main 方法。尝试这个:

java -classpath ojdbc7.jar oracle.jdbc.driver.OracleParameterMetaDataParser "你的 SQL 这里"

例如

java -classpath ojdbc7.jar oracle.jdbc.driver.OracleParameterMetaDataParser“更新人员设置姓氏=?,名字=?哪里人=?”

输出是您的 SQL 语句解析并转换为驱动程序内部使用的 SQL 查询来识别参数数据类型:

SQL:UPDATE PERSON SET LASTNAME=:1 , FIRSTNAME=:2 WHERE PERSONID=:3 SqlKind:UPDATE, Parameter Count=3 参数 SQL: SELECT LASTNAME, F, PERSONID FROM PERSON

但正如您在示例中看到的那样,FIRSTNAME 被错误地解析为“F”。

使用您在问题中提出的查询之一,结果是其中一个参数消失了......所以解析器说“5”参数但用于获取数据类型的内部查询确实只有“4”(HUMIDITY 有从 SELECT 中消失)。

java -classpath ojdbc7.jar oracle.jdbc.driver.OracleParameterMetaDataParser "UPDATE WEATHER_2 SET WEATHER=?, OBSTIME=TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF'), HUMIDITY=?, TEMP=? ID=在哪里?”

输出:

SQL:UPDATE WEATHER_2 SET WEATHER=:1 , OBSTIME=TO_TIMESTAMP(:2 ,'YYYY-MM-DD HH24:MI:SS.FF') , HUMIDITY=:3 , TEMP=:4 WHERE ID=:5
SqlKind:UPDATE , 参数 Count=5
参数 SQL: SELECT WEATHER, OBSTIME, TEMP, ID FROM WEATHER_2

如何修复?不知道,但正如我上面所说,使用 Oracle 11g ojdbc6.jar 驱动程序,相同的查询工作(甚至与 Oracle 12c 数据库连接......)。

行为非常随机。看起来它取决于 UPDATE 中使用的列的第一个字母。如果以F开头,H总是失败,不知道还有没有其他条件。

于 2016-01-27T09:53:03.050 回答
0

oracle 12.1.0.1.0 jdbc oracle.jdbc.driver.OracleParameterMetaDataParser 糟透了!

在我的测试中:

oracle.jdbc.driver.OracleParameterMetaDataParser.main(new String[]{"更新测试集 ORDX=?,A123=?,FABCDEFG=? where A2C=?"})

==>

SQL:update test set ORDX=:1 ,A123=:2 ,FABCDEFG=:3 where A2C=:4 SqlKind:UPDATE, Parameter Count=4 Parameter SQL: SELECT OX, A23, F, AC FROM test

以“O”开头的字段将修剪 1-2 个字符

以“F”开头的字段将修剪所有

以“A”开头的字段将修剪 1 个字符

在 oralce 12.1.0.2.0 上仍然存在问题:以“F”开头的字段将全部修剪

http://www.oracle.com/technetwork/database/features/jdbc/default-2280470.html

于 2016-04-08T04:25:02.807 回答
0

我遇到了同样的问题,使用 DBUtils 并从 ojdbc6 升级到 ojdbc7。然后我知道这是一个参数错误,所以我自己填写。像这样:

更新():

        Connection conn = dataSource.getConnection();
        PreparedStatement ps = conn.prepareStatement(sql.toUpperCase());
        this.fillStatement(ps, param);
        int rs = ps.executeUpdate();
        ps.close();
        conn.close();

填充语句():

private void fillStatement(PreparedStatement stmt, Object... params) throws SQLException {
    int i = 1;
    for (Object o: params){
        fill(stmt, i, o);
        i ++;
    }
}

private void fill(PreparedStatement stmt, int index, Object param) throws SQLException {
    if (param == null) {
        stmt.setObject(index, null);
    } else if (param instanceof String) {
        stmt.setString(index, (String) param);
    } else if (param instanceof Boolean) {
        stmt.setBoolean(index, (Boolean) param);
    } else if (param instanceof Integer) {
        stmt.setInt(index, (Integer) param);
    } else if (param instanceof Long) {
        stmt.setLong(index, (Long) param);
    } else if (param instanceof Double) {
        stmt.setDouble(index, (Double) param);
    } else if (param instanceof Float) {
        stmt.setFloat(index, (Float) param);
    } else if (param instanceof Short) {
        stmt.setShort(index, (Short) param);
    } else if (param instanceof Clob) {
        stmt.setClob(index, (Clob) param);
    } else if (param instanceof Blob) {
        stmt.setBlob(index, (Blob) param);
    } else if (param instanceof java.sql.Timestamp) {
        stmt.setTimestamp(index, (java.sql.Timestamp) param);
    } else if (param instanceof BigDecimal) {
        stmt.setBigDecimal(index, (BigDecimal) param);
    }else if (param instanceof java.sql.Time) {
        stmt.setTime(index, (java.sql.Time) param);
    }  else if (param instanceof java.sql.Date) {
        stmt.setDate(index, (java.sql.Date) param);
    } else if (param instanceof Date) {
        stmt.setDate(index, new java.sql.Date(((Date) param).getTime()));
    } else {
        stmt.setObject(index, param);
    }
}
于 2017-05-15T01:13:20.007 回答