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

最後の例である奇妙なÃ^またはÃ-に注意してください。大胆なテクストに注意してください。

...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()のようなものを使用する必要があると思います。おそらく、どういうわけか、値は文字コードとして解釈され(文字列として明示的にキャストされていないため)、奇妙な文字を引き起こします。

もう1つの推測は、データベースに送信する前に、実際に1500万のクエリをメモリ内に構築しているのでしょうか。または、各クエリは個別にDBに送信されますか?巨大な文字列をメモリに格納しようとしているという事実は、いくつかの問題を引き起こす可能性があります(ただし、ここで説明している問題を引き起こすことはないはずです)。

于 2012-07-18T17:44:06.887 に答える
1

巨大な更新を2つのCASEセレクターに置き換え、1つを各行のIN個別のステートメントに置き換えることを検討することをお勧めします。UPDATE問題の原因がこれではないことはわかっていますが、おそらくよりクリーンで効率的な解決策です。DBコネクタが実行ごとに複数のステートメントをサポートしている場合は、次のようにすることができます。

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ます。、、、またはがすでに文字列である場合driveTimeは、適切なJDBCメソッドを使用してそれらを適切にエスケープする必要があります。distanceID

@RobIIIによって提案されているように、SQLインジェクションの問題を自動的に処理するため、この種のプリペアドステートメントを使用する方がよいでしょう。

于 2012-07-18T18:18:38.043 に答える