Excel百万数据如何导入导出

1.前言

ExecutorType:批量操作执行器类型

在MyBatis中,ExecutorType是一种枚举类型,用于指定SQL语句执行的方式。其中,ExecutorType.BATCH和ExecutorType.SIMPLE是两种常见的执行方式

1. ExecutorType.SIMPLE:

  1. ExecutorType.SIMPLE是默认的执行方式。

  2. 每次执行SQL语句时,都会打开一个新的PreparedStatement对象。

  3. 每条SQL语句都会立即被执行并提交到数据库。

  4. 适用于常规的单个或少量SQL操作。

PreparedStatement对象是 Java 中用于执行预编译 SQL 语句的接口PreparedStatement 具有以下特点:①预编译②参数化查询(防止SQL注入)③性能优化

2. ExecutorType.BATCH:

  1. ExecutorType.BATCH会将一批SQL语句集中在一起批量执行,减少了与数据库的交互次数,提高性能。

  2. 多条SQL语句会一起提交到数据库执行,可以提升执行效率。

  3. 可以通过sqlSession.flushStatements()方法手动触发批量执行。

  4. 适用于需要执行大量SQL操作的场景,如批量插入、更新或删除多条记录。

  5. 综上所述,ExecutorType.SIMPLE适用于常规的单个或少量SQL操作,而ExecutorType.BATCH适用于需要批量执行大量SQL操作的场景,效率更高。选择适当的执行方式可根据业务需求和性能要求进行衡量。

3.ExecutorType.REUSE

  1. 当多次调用相同的SQL语句时,会重用已编译的SQL语句和执行计划。

  2. 适用于单条SQL语句的重复执行,例如在一个循环中多次执行相同的SQL语句。

  3. 每次执行都会创建一个新的Statement对象,但会重用已编译的SQL语句和执行计划,以提高执行效率。

综上所述,ExecutorType.SIMPLE适用于常规的单个或少量SQL操作,而ExecutorType.BATCH适用于需要批量执行大量SQL操作的场景,效率更高。选择适当的执行方式可根据业务需求和性能要求进行衡量。

3.常见的插入方式

第一种:单条插入语句(最慢的)

insert into student(name,age) values(#{name},#{age})

第二种:<foreach>标签,循环插入(效率高)

insert into student(name,age) values  

         <foreach collection="students" item="student" open="" close="" separator=",">                         (# {student.name},#{student.age})  

        </foreach>

4.百万数据 批量导入数据库

4.1 从Excel中获取数据

第一种:获取Excel所有数据

ExcelReader reader = ExcelUtil.getReader("d:/aaa.xlsx");​

reader.setSheet("Sheet1");  # setSheet()方法是设置读取Excel的那一页

List<Map<String,Object>> readAll = reader.readAll();

第二种:分批读取Excel中的数据

ExcelReader reader = ExcelUtil.getReader("d:/aaa.xlsx");

List<List<Object>> readAll = reader.read();​# read()

方法有三个参数:第一个参数:开始读取的行数

                             第二个参数:结束读取的行数

                             第三个参数:是否跳过第一行(因为大部分我们数据的第一行都是标题)

注意:hutool中读取的Excel数据会 将读到的数据,存入到内存中。

4.2开启批处理

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

Plain Text

ExceutorType.BATCH批处理,是批量操作sql语句,无论是单条插入的sql语句还是foreach插入的sql语句,都可以使用

目的是:将多条sql语句先拼接完成,不提交给数据库执行,等达到你设置的条件,或者某一个时刻,再统一将多条sql语句提交给数据库执行。减少了与数据库交互的次数,性能也会得到大幅度提升。

注意:在配置文件中 连接数据库的 url上加上 以下参数 `rewriteBatchedStatements=true`

rewriteBatchedStatements=true 是 MySQL JDBC驱动程序中的一个连接参数。rewriteBatchedStatements=true 是一个可以提高MySQL批量操作性能的参数

5.多线程导入数据库

  1. CountDownLatch

CountDownLatch 是一个同步辅助类,它允许一个或多个线程等待直到一组操作完成。这个类的主要作用是协调多个线程之间的执行顺序,确保所有线程都完成了某个任务后再继续执行后续代码。在 Java 中,CountDownLatch 的构造函数接受一个整数参数,表示需要等待的线程数量。当计数器的值变为 0 时,表示所有线程都已经完成了它们的任务,可以继续执行其他线程了。

CountDownLatch 维护了一个计数器,初始值为指定的数量。当一个或多个线程调用 await() 方法时,它们会被阻塞,直到计数器的值变为 0。而其他线程可以通过调用 countDown() 方法来减小计数器的值,当计数器的值变为 0 时,所有处于等待状态的线程都会被唤醒。需要注意的是,CountDownLatch 是一次性的,即计数器的值减为 0 后就不能再重置成其他值

 百万数据插入

public String upload(@RequestBody UploadInfo uploadInfo) throws Exception {
        String name = uploadInfo.getName();
        String base64 = uploadInfo.getBase64();
        String[] strArray = StrUtil.splitToArray(base64, "base64,");
        byte[] bytes = Base64.decode(strArray[1]);                                                                                                                                                                                 

        //用于创建一个基于字节数组的输入流。它允许你从一个字节数组中读取数据。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        // 使用Hutool读取Excel文件
        ExcelReader reader = ExcelUtil.getReader(byteArrayInputStream);
        //将读取到的 reader 转化为 List<Man>集合
        List<Person> persons = reader.readAll(Person.class);

        //StopWatch类是 Hutool 工具库中的类,用于测量代码执行时间
        StopWatch stopWatch = new StopWatch();
        //读取数据的结束时间同时也是写入数据库的开始时间
        stopWatch.start();
        //sqlSessionFactory是通过ioc容器注入的  设置其SqlSession的执行器格式ExecutorType.SIMPLE(默认)
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        //循环将List<Man>中的数据插入数据库
       for (Person person : persons) {
            mapper.insert(person);
        }

       //mapper.insertBatch(persons);
        sqlSession.commit();
        stopWatch.stop();
        sqlSession.close();
        System.out.println("插入数据库最终的结果为:" + stopWatch.getTotalTimeSeconds());

        return "ok";
    }
 

百万数据导出

@GetMapping("/write")
    public void exportExcel(HttpServletResponse response) throws IOException {
        // 创建Excel写入器   参数 true 表示追加数据,即在已有的 Excel 文件上追加新数据。如果设为 false,则会覆盖已有的数据。
        List<Person> person = personMapper.selectAll();
        // 创建ExcelWriter对象
        ExcelWriter writer = ExcelUtil.getWriter(true);
        int i = 0;
        while (true) {
            List<Person> list = person.stream().skip(i * 100000).limit(100000).parallel().collect(Collectors.toList());
            if (list.isEmpty()) {
                break;
            }
            writer.setSheet("person" + i);
            // 写入表头
            writer.addHeaderAlias("id", "Id");
            writer.addHeaderAlias("name", "姓名");
            writer.addHeaderAlias("age", "年龄");
            // 写入当前批次的数据
            writer.write(list, true);
            i++;
        }
        //response为HttpServletResponse对象   设置响应的内容类型为Excel文件
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
        //设置响应头,告诉浏览器以附件形式下载文件,文件名为test.xlsx。这样设置可以让浏览器弹出文件下载对话框。
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx");
        //获取响应输出流,它是用于将响应的数据发送给客户端的流。
        ServletOutputStream out = response.getOutputStream();
        //将Excel数据写入输出流。第二个参数为true表示追加写入,即将数据追加到已有的Excel文件中。
        writer.flush(out, true);
        writer.close();
        //关闭输出流
        out.close();
    }
 

多线程插入数据

@PostMapping
    public String upload(@RequestBody UploadInfo uploadInfo) throws Exception {
        String base64 = uploadInfo.getBase64();
        String[] strArray = StrUtil.splitToArray(base64, "base64,");
        byte[] bytes = Base64.decode(strArray[1]);
        //用于创建一个基于字节数组的输入流。它允许你从一个字节数组中读取数据。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        // 使用Hutool读取Excel文件
        ExcelReader reader = ExcelUtil.getReader(byteArrayInputStream);
        ExecutorService executor = Executors.newFixedThreadPool(10);
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        try {
            //存储读取的数据
            List<Person> students = null;
            Map<Integer, List<Person>> map = null;
            int start = 1;
            int end = 10000;
            //计时器
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            while (end <= 200000) {
                students = reader.read(0, start, end, Person.class);
                int i = 0;
                map = new HashMap<>();
                while (true) {
                    List<Person> list = students.stream().skip(i * 2000).limit(2000).parallel().collect(Collectors.toList());
                    if (list.isEmpty()) {
                        break;
                    }
                    map.put(i + 1, list);
                    i++;
                }
                CountDownLatch latch = new CountDownLatch(5);
                for (List<Person> students1 : map.values()) {
                    executor.submit(() -> {
                        mapper.insertBatch(students1);
                        latch.countDown();
                    });
                }
                latch.await();
                sqlSession.commit();
                start += 10000;
                end += 10000;
            }
            stopWatch.stop();
            System.out.println("插入数据库的时间为:" + stopWatch.getTotalTimeSeconds());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        } finally {
            executor.shutdown();
        }
        return null;
    }
 

 

  • 22
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

钟月一人

码字整理不易,感谢各位大佬支持

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

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

打赏作者

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

抵扣说明:

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

余额充值