Apache Dbutils 在更新 Sql 中更改列名
Posted
技术标签:
【中文标题】Apache Dbutils 在更新 Sql 中更改列名【英文标题】:Apache Dbutils changing column name in update Sql 【发布时间】:2015-08-20 09:49:40 【问题描述】:我在使用 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]
这可能是数据库的事情吗?此外,这仅发生在类型为 Date 或 Timestamp 的列中。
【问题讨论】:
向 My Oracle Support 提出问题。 【参考方案1】:我遇到了类似的问题。我认为这是 Oracle JDBC 7 驱动程序 (ojdbc7.jar) 中的错误。该错误可能在 PreparedStatement.getParameterMetaData 方法中。
此方法由 Apache DBUtils 内部使用。所以这不是 DBUtils 的 bug,而是 Oracle 12c 分发的 Oracle JDBC 驱动的 bug。
如果您使用 Oracle 11g ojdbc6.jar 驱动程序,Same Query 可能会正常工作。它至少对我有用。
如果要查看Oracle ojdbc7.jar 驱动程序内部如何错误处理Query,可以使用oracle.jdbc.driver.OracleParameterMetaDataParser 类中包含的main 方法。试试这个:
java -classpath ojdbc7.jar oracle.jdbc.driver.OracleParameterMetaDataParser "YOUR SQL HERE"
例如
java -classpath ojdbc7.jar oracle.jdbc.driver.OracleParameterMetaDataParser "更新人员集 LASTNAME=?, FIRSTNAME=? WHERE PERSONID=?”
输出是您的 SQL 语句解析并转换为驱动程序内部用于识别参数数据类型的 SQL 查询:
SQL:UPDATE PERSON SET LASTNAME=:1 , FIRSTNAME=:2 WHERE PERSONID=:3 SqlKind:UPDATE, Parameter Count=3 参数 SQL: SELECT LASTNAME, F, 人的人
但正如您在示例中看到的那样,FIRSTNAME 被错误地解析为“F”。
使用您在问题中提出的查询之一,结果是其中一个参数消失了......所以解析器说“5”参数,但用于获取数据类型的内部查询确实只有“4” (从 SELECT 中删除了 HUMIDITY)。
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=? WHERE 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,参数计数=5 参数 SQL:SELECT WEATHER、OBSTIME、TEMP、ID FROM WEATHER_2
如何解决?不知道,但正如我上面所说,使用 Oracle 11g ojdbc6.jar 驱动程序,相同的查询可以工作(甚至连接到 Oracle 12c 数据库......)。
这种行为非常随机。看起来它取决于 UPDATE 中使用的列的第一个字母。如果以F开头,H总是失败,不知道还有没有其他条件。
【讨论】:
关于 PreparedStatement.getParameterMetadata 上的问题,至少有 2 个其他错误已向 Oracle 公开:***.com/a/25431409/3371541 oracle 12.1.0.1.0 jdbc oracle.jdbc.driver.OracleParameterMetaDataParser 烂!【参考方案2】:oracle 12.1.0.1.0 jdbc oracle.jdbc.driver.OracleParameterMetaDataParser 太烂了!
在我的测试中:
oracle.jdbc.driver.OracleParameterMetaDataParser.main(new String[]"更新测试集 ORDX=?,A123=?,FABCDEFG=? where A2C=?")
==>
SQL:更新测试集 ORDX=:1 ,A123=:2 ,FABCDEFG=:3 where A2C=:4 SqlKind:更新,参数计数=4 参数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
【讨论】:
【参考方案3】:我遇到了同样的问题,使用 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();
fillStatement():
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);
【讨论】:
以上是关于Apache Dbutils 在更新 Sql 中更改列名的主要内容,如果未能解决你的问题,请参考以下文章