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

文章目录
  1. 1. 三种插入姿势
  2. 2. 日志验证
  3. 3. 源码分析
  • II. 其他
    1. 0. 项目
    2. 1. 一灰灰Blog
  • 前面介绍了jooq的三种批量插入方式,结果最近发现这里面居然还有一个深坑,我以为的批量插入居然不是一次插入多条数据,而是一条一条的插入…,这就有点尬了

    1. 三种插入姿势

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    /**
    * 通过Record执行批量添加
    *
    * 通过源码查看,这种插入方式实际上是单条单条的写入数据,和下面的一次插入多条有本质区别
    *
    * @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;
    }

    /**
    * 不基于自动生成的代码,来批量添加数据
    *
    * @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;
    }

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

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

    2. 日志验证

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

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

    1
    2
    3
    debug=false
    trace=false
    logging.level.org.jooq=DEBUG

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

    一个简单的测试case

    1
    2
    3
    4
    5
    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")));
    }

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 表结构中,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")));

    第一种批量插入失败

    第二种插入失败

    插入后结果

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

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

    3. 源码分析

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @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();
    }
    }

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

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

    II. 其他

    0. 项目

    系列博文

    项目源码

    1. 一灰灰Blog

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

    下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

    一灰灰blog


    打赏 如果觉得我的文章对您有帮助,请随意打赏。
    分享到