点击上方名片关注我,为你带来更多踩坑案例

系统设计-批量插入-LMLPHP

- 引言 -

    如果你是一个摸爬滚打几年的开发者,那么这个阶段,对系统设计的合理性绝对是衡量一个人水平的重要标准。

    一个好的设计不光能让你工作中避免很多麻烦,还能为你面试的时候增加很多谈资

    而且,不同设计之间理念都是有借鉴性参考性的,你见过的设计多了,思考的多了,再次面临一个问题的时候,就会有很多点子不由自主的冒出来。

    希望这个系列的文章,能够和大家互相借鉴参考,共同进步。

- 问题背景 -

     最近在做一个解析文本内容功能的时候,遇到了事务执行时间太长的问题,问题的具体分析可以见

    总而言之就是一个大批量、长json的解析,要往库中插入上千甚至上万条的关联数据。

- 问题分析 -

       首先肯定不能一条一条的插入了,都这个量级了,必须来批量插入(不能偷懒了)。

        批量插入,要么就是自己写sql拼参数,要么就是使用持久层框架现成的一些封装方法。

- JPA的批量插入 -

@Override
    public Integer batchInsertFile(List<File> fileList) {
        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO test_file " +
                "(project_id, fid, name, size, use_type, path, absolute_path, resolution, subfix, file_id, inner_location, create_uid, status, valid_status) " +
                "VALUES ");
        for (int i = 0; i < fileList.size(); i++) {
            sql.append(" (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            if (i != fileList.size() - 1) {
                sql.append(",");
            }
        }
        sql.append("on DUPLICATE key update project_id = VALUES(assets_id), name = VALUES(name), size = VALUES(size), use_type = VALUES(use_type)" +
                ", path = VALUES(path), absolute_path = VALUES(absolute_path), resolution = VALUES(resolution), subfix = VALUES(subfix), STATUS = VALUES(STATUS), valid_status = VALUES(valid_status)");
        Query query = entityManager.createNativeQuery(sql.toString());
        int paramIndex = 1;
        for (File file : fileList) {
            query.setParameter(paramIndex++, file.getProjectId());
            query.setParameter(paramIndex++, file.getFid());
            query.setParameter(paramIndex++, file.getName());
            query.setParameter(paramIndex++, file.getSize());
            query.setParameter(paramIndex++, file.getUseType());
            query.setParameter(paramIndex++, file.getPath());
            query.setParameter(paramIndex++, file.getAbsolutePath());
            query.setParameter(paramIndex++, file.getResolution());
            query.setParameter(paramIndex++, file.getSubfix());
            query.setParameter(paramIndex++, file.getFileId());
            query.setParameter(paramIndex++, file.getInnerLocation());
            query.setParameter(paramIndex++, file.getCreateUid());
            query.setParameter(paramIndex++, file.getStatus());
            query.setParameter(paramIndex++, file.getValidStatus());
        }
        return query.executeUpdate();
    }

    类似这样的方式,可以自己拼上唯一索引来处理插入重复的一些逻辑,或者使用insert ingore直接忽略。

    但是前面也说了,我批量插入的数据是往好几个表中插入,有层级关联关系的,上述这种方式拿不到插入的id,插入再查一次的话感觉有点脱了裤子放屁,不优雅。

- mybatis的批量插入 -

    找了一下,发现mybatis中支持批量插入后返回实体id,首先项目中引入mybatis

    yml文件加上

系统设计-批量插入-LMLPHP

    启动类加上

系统设计-批量插入-LMLPHP

    批量插入的方法

系统设计-批量插入-LMLPHP

    配置bean

系统设计-批量插入-LMLPHP

    然后就是写具体的方法了

系统设计-批量插入-LMLPHP

    最后就可以直接把封装好的批量数据插入了。

    使用这个方法的话入参中的id是会回写回来的。

- 结束语 -

    批量插入的方法有有很多,但是不得不说有一些方法是具有迷惑性的,会让你误以为是批量插入,但最后提交到数据库的sql语句依然是多条。

    所以不管使用哪种方法,我们最后还是要确认下,最后执行的sql是一条insert还是多条,这是最根本的点。

03-29 16:52