zoukankan      html  css  js  c++  java
  • 使用eazyExcel读取数据结合mybatis批量保存到数据库(优化批量保存)

    easy-excel (mybatis oracle 批量插入sql优化)

    数据量: 5万6 , 每行 30多个字段

    执行平均用时: 30秒(看电脑配置)

     

    准备依赖(2.1.1版本要求POI的版本必须为4.0及以上)

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.1.1</version>
    </dependency>

     

    EazyExcelUtil

    public class EazyExcelUtil {
        /**
         * 从Excel中读取文件,读取的文件是一个DTO类,该类必须继承BaseRowModel
         * 具体实例参考 : MemberMarketDto.java
         * 参考:https://github.com/alibaba/easyexcel
         * 字符流必须支持标记,FileInputStream 不支持标记,可以使用BufferedInputStream 代替
         * BufferedInputStream bis = new BufferedInputStream(new FileInputStream(...));
         */
        public static <T extends BaseRowModel> List<T> readExcel(final InputStream inputStream, final Class<? extends BaseRowModel> clazz) {
            if (null == inputStream) {
                throw new NullPointerException("the inputStream is null!");
            }
            ExcelListener<T> listener = new ExcelListener<>();
            // 这里因为EasyExcel-1.1.1版本的bug,所以需要选用下面这个标记已经过期的版本
            ExcelReader reader = new ExcelReader(inputStream,  valueOf(inputStream), null, listener);
            reader.read(new com.alibaba.excel.metadata.Sheet(1, 1, clazz));
            reader.finish();
            return listener.getRows();
        }
    ​
    ​
        public static void writeExcel(final File file, List<? extends BaseRowModel> list) {
            try (OutputStream out = new FileOutputStream(file)) {
                ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
                //写第一个sheet,  有模型映射关系
                Class<? extends BaseRowModel> t = list.get(0).getClass();
                Sheet sheet = new Sheet(1, 0, t);
                writer.write(list, sheet);
                writer.finish();
            } catch (IOException e) {
    //            log.warn("fail to write to excel file: file[{}]", file.getName(), e);
                throw new SysException("写入excel 异常");
            }
        }
    ​
    ​
        /**
         * 根据输入流,判断为xls还是xlsx,该方法原本存在于easyexcel 1.1.0 的ExcelTypeEnum中。
         */
        public static ExcelTypeEnum valueOf(InputStream inputStream) {
            try {
                FileMagic fileMagic = FileMagic.valueOf(inputStream);
                if (FileMagic.OLE2.equals(fileMagic)) {
                    return ExcelTypeEnum.XLS;
                }
                if (FileMagic.OOXML.equals(fileMagic)) {
                    return ExcelTypeEnum.XLSX;
                }
                throw new IllegalArgumentException("excelTypeEnum can not null");
    ​
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    ​
    }

     

    ExcelListener 监听器

    public class ExcelListener <T extends BaseRowModel> extends AnalysisEventListener<T> {
    ​
        private final List<T> rows = new ArrayList<>();
    ​
        @Override
        public void invoke(T t, AnalysisContext analysisContext) {
    ​
            rows.add(t);
        }
    ​
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    ​
        }
    ​
        public List<T> getRows() {
            return rows;
        }
    }

     

    DTO实体对应excel

    public class Demo extends BaseRowModel {    //需要继承BaseRowModel
    ​
        @ExcelProperty(index = 0)   //指定字段对应excel的某列
        private String name;//get...set...
    }

     

    Dao层

    public interfase DemoDao  { 
        //这里只是模拟
        void save(@Param("list") List<Demo> list);
        
    }

     

    mapper

    <insert id="save">
        insert into demo (name)
        <foreach close=")" collection="list" item="item" index="index" open="(" separator="union">
            select
            #{item.name}
            from dual
        </foreach>
    </insert>

     

    service

    @Service
    @
    Transactional
    public class DemoService{
      
    public void save(MultipartFile file, String year) {
        int divNum = 50;    //分组保存数量(有foreach的情况下20到50条的性能最好),否则使用单条保存
        List<ZfZhiFuLingData> list = null;
        //读取excel数据
        try {
               fis = file.getInputStream();
               list = EazyExcelUtil.readExcel(new BufferedInputStream(fis), Demo.class);
            } catch (IOException e) {
                    throw new SysException("文件数据不符合规定,请重新上传" + e.getMessage());
            } finally {
                if (null != fis) {
                    try {
                         fis.close();
                    } catch (IOException e) {
                         e.printStackTrace();
                }
            }
         }
        //
        SqlSession session = sessionFactory.openSession(ExecutorType.BATCH);
        DemoDao mapper = session.getMapper(DemoDao.class);
        if (list.size() > 0) {
                //为了防止SQL语句超出长度出错,分成几次插入
                if (list.size() <= divNum) {
                    mapper.save(list);
                } else {
                    int length = list.size();
                    // 计算可以分成多少组
                    int num = (length + divNum - 1) / divNum;
                    for (int i = 0; i < num; i++) {
                        // 开始位置
                        int fromIndex = i * divNum;
                        // 结束位置
                        int toIndex = (i + 1) * divNum < length ? (i + 1) * divNum : length;
                        mapper.save(list.subList(fromIndex, toIndex));
                    }
                }
                session.flushStatements();
         }
      }
    }
    }

     

    Controller层就自己写了

  • 相关阅读:
    JavaWeb学习笔记
    IDEA环境配置里的一些error
    python库之argparse
    Burpsuite模块—-Intruder模块详解
    Burpsuite使用指南
    kali学习wiki
    用Flask 实现文件服务器(包含docker版本)
    ubuntu Nginx+tomcat 部署web项目
    python测试开发工具库汇总(转载)
    屏幕截图小工具的制作过程问题记录 python PIL pynput pyautogui pyscreeze
  • 原文地址:https://www.cnblogs.com/liweixml/p/13713334.html
Copyright © 2011-2022 走看看