系统设计-批量插入

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

4d87260b71da840426fb3ce592ed184d.png

- 引言 -

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

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

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

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

- 问题背景 -

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

连接池满了怎么办?

unhappy404,公众号:java排坑日记排坑日记-连接池满了?

    总而言之就是一个大批量、长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文件加上

4ad290e754ac5d32a584b640e1ab1e6a.png

    启动类加上

dd4b5a21d86499bae1db007e0bce9284.png

    批量插入的方法

f848d9c854a4bd982231b1274275c08d.png

    配置bean

3b072192de97c452bec36f3c1bfd9a31.png

    然后就是写具体的方法了

b83bd37b9fd9254023bb65d307cf7c7a.png

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

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

- 结束语 -

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

unhappy404

感谢老板打赏!!!爱您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值