【SpringBoot DB系列】Jooq批量寫入采坑記錄

image

【SpringBoot DB系列】Jooq批量寫入采坑記錄

前面介紹了jooq的三種批量插入方式,結(jié)果最近發(fā)現(xiàn)這里面居然還有一個(gè)深坑,我以為的批量插入居然不是一次插入多條數(shù)據(jù),而是一條一條的插入...,這就有點(diǎn)尬了

1. 三種插入姿勢(shì)

關(guān)于項(xiàng)目創(chuàng)建以及jooq的相關(guān)使用姿勢(shì),推薦查看之前的博文: 【DB系列】Jooq之新增記錄使用姿勢(shì)

下面是我們采用的三種批量插入方式

/**
 * 通過Record執(zhí)行批量添加
 *
 * 通過源碼查看,這種插入方式實(shí)際上是單條單條的寫入數(shù)據(jù),和下面的一次插入多條有本質(zhì)區(qū)別
 *
 * @param list
 * @return
 */
public boolean batchSave(List<PoetBO> list) {
    List<PoetPO> poList = list.stream().map(this::bo2po).collect(Collectors.toList());
    int[] ans = dsl.batchInsert(poList).execute();
    System.out.println(JSON.toJSONString(ans));
    return true;
}

/**
 * 類sql寫法,批量添加
 *
 * @param list
 * @return
 */
public boolean batchSave2(List<PoetBO> list) {
    InsertValuesStep2<PoetPO, Integer, String> step = dsl.insertInto(table).columns(table.ID, table.NAME);
    for (PoetBO bo : list) {
        step.values(bo.getId(), bo.getName());
    }
    return step.execute() > 0;
}

/**
 * 不基于自動(dòng)生成的代碼,來批量添加數(shù)據(jù)
 *
 * @param list
 * @return
 */
public boolean batchSave3(List<PoetBO> list) {
    InsertQuery insertQuery = dsl.insertQuery(DSL.table("poet"));
    for (PoetBO bo : list) {
        insertQuery.addValue(DSL.field("id", Integer.class), bo.getId());
        insertQuery.addValue(DSL.field("name", String.class), bo.getName());
        insertQuery.newRecord();
    }

    return insertQuery.execute() > 0;
}

請(qǐng)注意上面的三種批量插入方式,基本上對(duì)應(yīng)的就是jooq的三種常見的用法

  • 直接借助自動(dòng)生成的Record類來操作
  • 類sql的拼接寫法,基本上我們平時(shí)的sql怎么寫,這里就怎么用
  • InsertQuery:借助jooq提供的各種Query類來執(zhí)行目標(biāo)操作

2. 日志驗(yàn)證

上面三種寫法中,第一種批量插入方式,并不是我們傳統(tǒng)理解的一次插入多條記錄,相反它是一條一條的插入的,我們可以通過開啟jooq的日志來查看一些執(zhí)行的sql情況

配置文件 application.properties,添加下面的配置

debug=false
trace=false
logging.level.org.jooq=DEBUG

如果有自己的logback.xml配置文件,可以調(diào)整一下日志級(jí)別,將jooq的debug日志放出來

一個(gè)簡單的測(cè)試case

public void test() {
  this.batchSave(Arrays.asList(new PoetBO(14, "yh"), new PoetBO(15, "yhh")));
  this.batchSave2(Arrays.asList(new PoetBO(16, "yihui"), new PoetBO(17, "yihuihui")));
  this.batchSave3(Arrays.asList(new PoetBO(18, "YiHui"), new PoetBO(19, "YiHuiBlog")));
}
image

從上面的sql來看,后面兩個(gè)確實(shí)是一次插入多條,但是第一個(gè),也沒有將具體執(zhí)行的sql打印出來,所有不看源碼的話,也沒有辦法實(shí)錘是一條一條插入的

為了驗(yàn)證這個(gè)問題,一個(gè)簡單的解決辦法就是批量插入兩條數(shù)據(jù),第一條正常,第二條異常,如果第一條插入成功,第二條失敗那就大概率是單個(gè)插入的了

// 表結(jié)構(gòu)中,name的字段最大為20,下面插入的第二條數(shù)據(jù)長度超限
try {
    this.batchSave(Arrays.asList(new PoetBO(14, "yh"), new PoetBO(15, "1234567890098765432112345")));
} catch (Exception e) {
    e.printStackTrace();
}

try {
    this.batchSave2(Arrays.asList(new PoetBO(16, "yihui"), new PoetBO(17, "1234567890098765432112345")));
} catch (Exception e) {
    e.printStackTrace();
}
this.batchSave3(Arrays.asList(new PoetBO(18, "YiHui"), new PoetBO(19, "YiHuiBlog")));

第一種批量插入失敗

image

第二種插入失敗

image

插入后結(jié)果

image

請(qǐng)注意上面的報(bào)錯(cuò),以及最終插入的結(jié)果,第一種插入方式一個(gè)插入成功一個(gè)失?。坏诙N批量插入方式,兩條都插入失??;

通常情況下,一次插入多條數(shù)據(jù)時(shí),一個(gè)插入失敗,會(huì)導(dǎo)致整個(gè)插入都失敗,如下

image

3. 源碼分析

上面是從日志以及結(jié)果表現(xiàn)來推測(cè)實(shí)際的執(zhí)行情況,接下來就需要從源碼角度來看一下,是否真的是單個(gè)的執(zhí)行了

省略掉具體的定位過程,直接找到org.jooq.impl.BatchCRUD#execute,對(duì)應(yīng)的代碼

@Override
public final int[] execute() throws DataAccessException {

    // [#1180] Run batch queries with BatchMultiple, if no bind variables
    // should be used...
    if (executeStaticStatements(configuration.settings())) {
        return executeStatic();
    }
    else {
        return executePrepared();
    }
}

上面有兩種插入方式,對(duì)于插入的核心邏輯一樣

image

遍歷集合,獲取單個(gè) record,執(zhí)行 CURD

image

II. 其他

0. 項(xiàng)目

系列博文

項(xiàng)目源碼

1. 一灰灰Blog

盡信書則不如,以上內(nèi)容,純屬一家之言,因個(gè)人能力有限,難免有疏漏和錯(cuò)誤之處,如發(fā)現(xiàn)bug或者有更好的建議,歡迎批評(píng)指正,不吝感激

下面一灰灰的個(gè)人博客,記錄所有學(xué)習(xí)和工作中的博文,歡迎大家前去逛逛

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容