java向mysql数据库批量插入大量数据

首先看下我们的目标:向mysql数据库中批量插入10000条数据

操作环境:Mysql和Java代码都运行在我本地Windows电脑(i7处理器,4核,16G运行内存,64位操作系统

1、JPA单线程执行

代码省略,大概需要39S左右

2、JPA多线程执行 

大概需要37S左右,并没有想象中的快很多

原因: 多线程只是大大提高了程序处理数据的时间,并不会提高插入数据库的时间,相反在我这边JPA的框架下,多线程也就意味着多连接,反而更加消耗数据库性能

package com.example.demo.controller;

 

import com.example.demo.entity.Student;

import com.example.demo.service.StudentServiceInterface;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

 

import javax.xml.bind.ValidationException;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

@RestController

@RequestMapping("/student")

public class StudentController {

 

    @Autowired

    private StudentServiceInterface studentServiceInterface;

 

    // 来使主线程等待线程池中的线程执行完毕

    private CountDownLatch threadsSignal;

 

    // 每个线程处理的数据量

    private static final int count = 1000;

    // 我的电脑为4核 线程池大小设置为2N+1

    private static ExecutorService execPool = Executors.newFixedThreadPool(9);

     

    /**

     * 多线程保存

     *

     * @return

     * @throws ValidationException

     */

    @GetMapping()

    public String saveStudentEnableThread() throws ValidationException {

        Long begin = new Date().getTime();

        // 需要插入数据库的数据

        List list = new ArrayList<>();

        for (int i = 0; i < 10000; i++) {

            Student student = new Student();

            student.setName("张三");

            student.setAge(10);

            list.add(student);

        }

        try {

            if (list.size() <= count) {

                threadsSignal = new CountDownLatch(1);

                execPool.submit(new InsertDate(list));

            } else {

                List> lists = dealData(list, count);

                threadsSignal = new CountDownLatch(lists.size());

                for (List students : lists) {

                    execPool.submit(new InsertDate(students));

                }

            }

            threadsSignal.await();

        } catch (Exception e) {

            System.out.println(e.toString() + " 错误所在行数:" + e.getStackTrace()[0].getLineNumber());

        }

        // 结束时间

        Long end = new Date().getTime();

        return "10000条数据插入花费时间 : " + (end - begin) / 1000 + " s";

    }

 

    /**

     * 数据组装

     * 把每个线程要处理的数据 再组成一个List

     * 我这边就是把10000条数据 组成 10个1000条的集合

     *

     * @param target 数据源

     * @param size   每个线程处理的数量

     * @return

     */

    public static List> dealData(List target, int size) {

        List> threadList = new ArrayList>();

        // 获取被拆分的数组个数

        int arrSize = target.size() % size == 0 ? target.size() / size : target.size() / size + 1;

        for (int i = 0; i < arrSize; i++) {

            List students = new ArrayList();

            //把指定索引数据放入到list中

            for (int j = i * size; j <= size * (i + 1) - 1; j++) {

                if (j <= target.size() - 1) {

                    students.add(target.get(j));

                }

            }

            threadList.add(students);

        }

        return threadList;

    }

 

    /**

     * 内部类,开启线程批量保存数据

     */

    class InsertDate extends Thread {

        List list = new ArrayList();

        public InsertDate(List students) {

            list = students;

        }

        public void run() {

            try {

                // 与数据库交互

                studentServiceInterface.save(list);

                threadsSignal.countDown();

            } catch (ValidationException e) {

                e.printStackTrace();

            }

        }

    }

}

 3、传统JDBC插入

大概需要8S左右,相较于前两种方式已经快很多了,代码如下:

package com.example.demo.controller;

 

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

 

import javax.xml.bind.ValidationException;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.util.Date;

 

@RestController

@RequestMapping("/student1")

public class StudentController1 {

 

    @GetMapping()

    public String saveStudentEnableThread() throws ValidationException {

        // 开始时间

        Long begin = new Date().getTime();

        Connection connection = null;

        try {

            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db01?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true", "admin", "123456");//获取连接

            if (connection != null) {

                System.out.println("获取连接成功");

            } else {

                System.out.println("获取连接失败");

            }

            //这里必须设置为false,我们手动批量提交

            connection.setAutoCommit(false);

            //这里需要注意,SQL语句的格式必须是预处理的这种,就是values(?,?,...,?),否则批处理不起作用

            PreparedStatement statement = connection.prepareStatement("insert into student(id,`name`,age) values(?,?,?)");

            // 塞数据

            for (int i = 0; i < 10000; i++) {

                statement.setInt(1, i+1);

                statement.setString(2, "张三");

                statement.setInt(3, 10);

                //将要执行的SQL语句先添加进去,不执行

                statement.addBatch();

            }

            // 提交要执行的批处理,防止 JDBC 执行事务处理

            statement.executeBatch();

            connection.commit();

            // 关闭相关连接

            statement.close();

            connection.close();

        } catch (Exception e) {

            e.printStackTrace();

        }

        // 结束时间

        Long end = new Date().getTime();

        // 耗时

        System.out.println("10000条数据插入花费时间 : " + (end - begin) / 1000 + " s");

        return "10000条数据插入花费时间 : " + (end - begin) / 1000 + " s";

    }

 

}

 4、最后检查一下数据是否成功存库,一共30000条,没有丢数据

完成!

总结:

 小伙伴们有兴趣想了解更多相关学习资料请点赞收藏+评论转发+关注

猜你喜欢

转载自blog.csdn.net/m0_67698950/article/details/123870480