ラベル MySQL の投稿を表示しています。 すべての投稿を表示
ラベル MySQL の投稿を表示しています。 すべての投稿を表示

2019年2月27日水曜日

MySQL JDBC での batchInsert

Java で JDBC を使用して MySQL への batchInsert (バルクインサート) で嵌った・・・

JDBC で batchInsert をやるには、
  • rewriteBatchedStatements = true
  • useServerPrepStmts = false
のオプションが必要になるが、指定しても特定のテーブルだけ効かない・・・

テーブル
CREATE TABLE testtbl(selector_type INT);

Java
Class.forName("com.mysql.jdbc.Driver").newInstance();

Properties prop = new Properties();
prop.setProperty("user", "testuser");
prop.setProperty("password", "password");
prop.setProperty("characterEncoding", "utf8");
prop.setProperty("rewriteBatchedStatements", "true");
prop.setProperty("useServerPrepStmts", "false");

try (Connection con= DriverManager.getConnection("jdbc:mysql://localhost/testdb", prop)) {
  PreparedStatement stmt = con.prepareStatement("INSERT INTO testtbl (selector_type) VALUES (?)");
  for (int i = 0; i < 10; ++i) {
    stmt.setInt(1,  i);
    stmt.addBatch();
  }

  stmt.executeBatch();
}

結果
2019-02-27T02:28:18.112397Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (0);
2019-02-27T02:28:18.112734Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (1);
2019-02-27T02:28:18.112853Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (2);
2019-02-27T02:28:18.113839Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (3);
2019-02-27T02:28:18.113953Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (4);
2019-02-27T02:28:18.114038Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (5);
2019-02-27T02:28:18.114121Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (6);
2019-02-27T02:28:18.114202Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (7);
2019-02-27T02:28:18.114291Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (8);
2019-02-27T02:28:18.114370Z        19 Query     INSERT INTO testtbl (selector_type) VALUES (9)

VALUES のあとにスペースが必要との情報もあったが、既についてる・・・

JDBC ドライバーのソースを追ってみたところ、PreparedStatement クラスに

if (StringUtils.indexOfIgnoreCase(statementStartPos, sql, "SELECT", "\"'`", "\"'`", StringUtils.SEARCH_MODE__MRK_COM_WS) != -1) {
  return false;
}
的なコードが・・・

SELECT INSERT を除外しているようだが、もしやということで、カラム名をバッククウォートで囲ったところ

Java
snip ...

  PreparedStatement stmt = con.prepareStatement("INSERT INTO testtbl (`selector_type`) VALUES (?)");

snip ...

結果
2019-02-27T02:28:39.536756Z        20 Query     INSERT INTO testtbl (`selector_type`) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)
連結されて、1 文で実行されることに!
SQL 文の中に SELECT という文字があるとダメな模様。

さらに調べてみると既に報告が上がっていた。
https://bugs.mysql.com/bug.php?id=81468
2016 年 5 月・・・