0

我目前正在计算值以填充 1500 万条记录的数据库。第一个 7 磨机刚刚好,但是现在我的更新查询开始出现问题:现在 & 然后一个随机字母变成了一些乱码。在java中,我生成查询:

String updateSql = "UPDATE VanNaar SET time = CASE ID ";
        for (int i = 0; i < routes.size(); i++) {
            updateSql += " WHEN " + routes.get(i).ID + " THEN  " + routes.get(i).driveTime;
        }
        updateSql += " END, ";
        updateSql += " distance = CASE ID ";
        for (int i = 0; i < routes.size(); i++) {
            updateSql += " WHEN " + routes.get(i).ID + " THEN  " + routes.get(i).distance;
        }
        updateSql += " END WHERE id IN (";
        for (int i = 0; i < routes.size(); i++) {
            updateSql += routes.get(i).ID + ",";
        }
        updateSql = updateSql.substring(0, updateSql.length() - 1);
        updateSql += ");";

如前所述,效果很好。以下是 Java 现在向我提出的问题:

...MySQL server version for the right syntax to use near '×HEN 8284022 THEN  999.999 WHEN 8284023 THEN  3791.0 WHEN 8284024 THEN  378...

或者

...MySQL server version for the right syntax to use near 'WÈEN 7468574 THEN  2273.0 WHEN 7468575 THEN  2410.0 WHEN 7468576 THEN  2472.0 W' at line 1

注意奇怪的Ã^Ã-,最后一个例子,请注意大胆的 tekst:

...MySQL server version for the right syntax to use near **'Â** WHEN 7228125 THEN 48590.0 WHEN 7228126 THEN 47910.0 WHEN 7228127 THEN...

...

更新:似乎变得更糟了..:

 Unknown column '9°22331' in 'where clause'
4

2 回答 2

2

我不是 Java 专家,但您不应该首先使用StringBuilder吗?甚至可能使用准备好的语句?您可以使用 stringbuilder 构建准备好的语句,而不是

updateSql += " WHEN " + routes.get(i).ID + " THEN  " + routes.get(i).driveTime;

你会在任何地方做类似的事情

myStrngBldr.append(" WHEN ? THEN  ?");

或者

myStrngBldr.append(" WHEN @foo1 THEN @foo2");

如果支持命名参数(不知道),然后添加实际参数:

myPrepdStmt = myConn.prepareStatement(myStrngBldr.toString());

myPrepdStmt.setInt(1, routes.get(i).ID);
myPrepdStmt.setFloat(2, routes.get(i).driveTime);
...
myPrepdStmt.executeUpdate();

这个页面应该可以帮助你。

究竟是什么导致了“奇怪的格式错误的字符串”:我不知道。我最好的猜测是你必须在所有这些 ID 和其他非字符串值上使用类似 .ToString() 的东西,因为你要连接一个字符串。也许,不知何故,这些值被解释为字符码(因为它们没有明确地转换为字符串),从而导致奇怪的字符。

另一个猜测是:在将它们发送到数据库之前,您是否真的在内存中构建了 1500 万个查询?还是每个查询都单独发送到数据库?也许您试图在内存中存储一​​个巨大的字符串这一事实会导致一些问题(尽管它不应该导致您在此处描述的问题)。

于 2012-07-18T17:44:06.887 回答
1

您可能需要考虑用两个CASE选择器和一个IN用每行的单独UPDATE语句替换巨大的更新。我知道问题不是由此引起的,但它可能是一种更清洁、更有效的解决方案。如果您的数据库连接器支持每次执行多个语句,您可以执行以下操作:

int batchSize = 0;
StringBuilder sb = new StringBuilder();
for (Route r: routes) {
    sb.append("UPDATE VanNaar SET")
      .append(" time = '").append(r.driveTime).append("',")
      .append(" distance = '").append(r.distance).append("'")
      .append(" WHERE ID = '").append(r.ID).append("'; ");
    if (++batchSize == BATCH_SIZE) {
        connector.exec(sb.toString());
        sb = new StringBuilder();
        batchSize = 0;
    }
}
if (sb.length() > 0) {
    connector.exec(sb.toString());
}

这将让我们StringBuilder负责将任何基础值类型转换为String. 如果driveTimedistanceID已经是字符串,那么您必须使用适当的 JDBC 方法正确地转义它们。

正如@RobIII所建议的那样,您最好对这类事情使用准备好的语句,因为它们会自动处理 SQL 注入问题。

于 2012-07-18T18:18:38.043 回答