spring boot 批量删除集合怎么写 springboot批量新增_批量插入


【SpringBoot DB系列】Jooq批量写入采坑记录

前面介绍了jooq的三种批量插入方式,结果最近发现这里面居然还有一个深坑,我以为的批量插入居然不是一次插入多条数据,而是一条一条的插入...,这就有点尬了

1. 三种插入姿势

关于项目创建以及jooq的相关使用姿势,推荐查看之前的博文: 【DB系列】Jooq之新增记录使用姿势

下面是我们采用的三种批量插入方式

/** * 通过Record执行批量添加 * * 通过源码查看,这种插入方式实际上是单条单条的写入数据,和下面的一次插入多条有本质区别 * * @param list * @return */public boolean batchSave(List list) {    List 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 list) {    InsertValuesStep2 step = dsl.insertInto(table).columns(table.ID, table.NAME);    for (PoetBO bo : list) {        step.values(bo.getId(), bo.getName());    }    return step.execute() > 0;}/** * 不基于自动生成的代码,来批量添加数据 * * @param list * @return */public boolean batchSave3(List 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;}

请注意上面的三种批量插入方式,基本上对应的就是jooq的三种常见的用法

  • 直接借助自动生成的Record类来操作
  • 类sql的拼接写法,基本上我们平时的sql怎么写,这里就怎么用
  • InsertQuery:借助jooq提供的各种Query类来执行目标操作

2. 日志验证

上面三种写法中,第一种批量插入方式,并不是我们传统理解的一次插入多条记录,相反它是一条一条的插入的,我们可以通过开启jooq的日志来查看一些执行的sql情况

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

debug=falsetrace=falselogging.level.org.jooq=DEBUG

如果有自己的logback.xml配置文件,可以调整一下日志级别,将jooq的debug日志放出来

一个简单的测试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")));}


spring boot 批量删除集合怎么写 springboot批量新增_spring boot 高性能批量新增_02


从上面的sql来看,后面两个确实是一次插入多条,但是第一个,也没有将具体执行的sql打印出来,所有不看源码的话,也没有办法实锤是一条一条插入的

为了验证这个问题,一个简单的解决办法就是批量插入两条数据,第一条正常,第二条异常,如果第一条插入成功,第二条失败那就大概率是单个插入的了

// 表结构中,name的字段最大为20,下面插入的第二条数据长度超限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")));

第一种批量插入失败


spring boot 批量删除集合怎么写 springboot批量新增_sql_03


第二种插入失败


spring boot 批量删除集合怎么写 springboot批量新增_批量插入_04


插入后结果


spring boot 批量删除集合怎么写 springboot批量新增_spring boot 高性能批量新增_05


请注意上面的报错,以及最终插入的结果,第一种插入方式一个插入成功一个失败;第二种批量插入方式,两条都插入失败;

通常情况下,一次插入多条数据时,一个插入失败,会导致整个插入都失败,如下


spring boot 批量删除集合怎么写 springboot批量新增_批量插入_06


3. 源码分析

上面是从日志以及结果表现来推测实际的执行情况,接下来就需要从源码角度来看一下,是否真的是单个的执行了

省略掉具体的定位过程,直接找到org.jooq.impl.BatchCRUD#execute,对应的代码

@Overridepublic 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();    }}

上面有两种插入方式,对于插入的核心逻辑一样


spring boot 批量删除集合怎么写 springboot批量新增_spring boot 高性能批量新增_07


遍历集合,获取单个 record,执行 CURD


spring boot 批量删除集合怎么写 springboot批量新增_数据_08


II. 其他

0. 项目

系列博文

  • 【SpringBoot DB系列】Jooq之记录更新与删除
  • 【SpringBoot DB系列】Jooq之新增记录使用姿势
  • 【SpringBoot DB系列】Jooq代码自动生成
  • 【SpringBoot DB系列】Jooq初体验

项目源码

  • 工程:https://github.com/liuyueyi/spring-boot-demo
  • 项目源码: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/108-jooq-curd

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激