簡體   English   中英

Java 用於循環與批處理 SQL

[英]Java For loop with batch SQL

我有個問題。 現在我正在使用 JOOQ 使用以下代碼在我的數據庫中插入大約 100.000 條記錄:

try (Connection conn = DriverManager.getConnection(SqlConn.getURL(), SqlConn.getUSERNAME(), SqlConn.getPASSWORD())) {
    DSLContext create = DSL.using(conn, SQLDialect.MYSQL);

    for (String key : trendlines.keySet()) {
        for (Trendline trendline : trendlines.get(key)) {
            String sql = createTrendlineQuery(trendline);
            create.fetch(sql);
        }
    }

}
catch (Exception e) {
    e.printStackTrace();
}

使用 function createTrendlineQuery()

private String createTrendlineQuery(Trendline trendline) {

    return "INSERT INTO Trendline (openTime, market, coin, period, metric, number, slope, interceptY, percentage, formula, data) VALUES (" + 
    trendline.getOpenTime() + ", '" +
    trendline.getMarket() + "', '" +
    trendline.getCoin() + "', '" +
    trendline.getPeriod() + "', '" +
    trendline.getFormula() + "') " +
    "ON DUPLICATE KEY UPDATE " + 
    "openTime = " + trendline.getOpenTime() + ", " +
    "market = '" + trendline.getMarket()+ "', " +
    "coin = '" + trendline.getCoin() + "', " +
    "period = '" + trendline.getPeriod() + "', " +
    "formula = '" + trendline.getFormula() + "';";

}

但這給我的互聯網/數據庫帶來了很大的負擔,所以我發現你可以為大數據進行批量插入。 我在 JOOQ 中找到了關於批量插入的以下頁面: https://www.jooq.org/doc/3.14/manual/sql-execution/batch-execution/ 現在我認為這是我需要的,但我有一個問題。 該示例在我的情況下如下所示:

try (Connection conn = DriverManager.getConnection(SqlConn.getURL(), SqlConn.getUSERNAME(), SqlConn.getPASSWORD())) {
    DSLContext create = DSL.using(conn, SQLDialect.MYSQL);

    create.batch(create.insertInto(DSL.table("Trendline"), DSL.field("openTime"), DSL.field("market"), DSL.field("coin")  ).values((Integer) null, null, null))
        .bind(                           trendline.getOpenTime() , trendline.getMarket() , trendline.getCoin()  )
        .bind(                           trendline.getOpenTime() , trendline.getMarket() , trendline.getCoin()  )
        .bind(                           trendline.getOpenTime() , trendline.getMarket() , trendline.getCoin()  )
        .bind(                           trendline.getOpenTime() , trendline.getMarket() , trendline.getCoin()  )
        .execute();

}
catch (Exception e) {
    e.printStackTrace();
}

除了我需要在create.batch()之間放置 2 個for-loops以編程方式創建插入。 如何插入for loops ,我是否使用了正確的方式插入來減少 Internet 流量和數據庫壓力?

使用BatchedConnection作為快速修復

將現有 jOOQ 代碼(或任何基於 JDBC 的代碼)轉換為批處理 JDBC 交互的最簡單解決方案是使用 jOOQ 的BatchedConnection

create.batched((Connection c) -> {
    // Now work with this Connection c, instead of your own Connection and all the statements
    // will be buffered and batched, e.g.
    DSL.using(c).insertInto(...).values(...).execute();
});

使用您嘗試使用的批次 API

您只需將BatchBindStep分配給循環中的局部變量即可:

BatchBindStep step = create.batch(query);

for (...) 
    step = step.bind(...);

step.execute();

使用進口API

使用導入 API 假設您正在使用代碼生成器並且您有通常的 static 導入

import static org.jooq.impl.DSL.*;
import static com.example.generated.Tables.*;

寫這個:

create.loadInto(TRENDLINE)
      .onDuplicateKeyUpdate()
      .loadArrays(trendlines
          .values()
          .stream()
          .map(t -> new Object[] { 
              t.getOpenTime(),
              t.getMarket(),
              t.getCoin(),
              t.getPeriod(),
              t.getFormula()
              /* And the other fields which you partially omitted */
          })
          .toArray(Object[][]::new)
      )
      .fields(
          TRENDLINE.OPENTIME,
          TRENDLINE.MARKET,
          TRENDLINE.COIN,
          TRENDLINE.PERIOD,
          TRENDLINE.FORMULA
          /* And the other fields which you partially omitted */
      )
      .execute();

另請參閱以下部分:

  • 節流(您可能想要使用這些值來找到最適合您的系統的值)
  • 錯誤處理

這可能是有趣的。 如果輸入Object[][]變得太大,您可以手動分塊您的輸入trendlines.values()集合。 如果按鍵排序你的 map 真的很重要(我不應該從你的問題中看出),然后寫這個:

trendlines
    .keySet()
    .stream()
    .flatMap(k -> trendlines.get(k).stream())
    .map(t -> new Object[] { ... })
    ...

對你自己的嘗試的一些評論

  • 您正在調用create.fetch(sql) ,而實際上您的語句是具有更新計數的查詢,因此在這種情況下,您可能想改用create.execute(sql)
  • 使用 jOOQ 時請不要連接 SQL 字符串! 即使使用普通的 SQL 模板也不需要連接 SQL 字符串 您將遇到語法錯誤和 SQL 注入。 請始終使用綁定變量。
  • 我真的推薦你使用 jOOQ 的代碼生成器。 當您使用代碼生成器時,使用 jOOQ 的大部分好處就會出現。 避免代碼生成的有效原因包括當您的模式是動態的並且在運行時未知時。 這幾乎是不使用代碼生成的唯一原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM