Mybatis批量插入的三种实现方法

 更新时间:2023年10月30日 09:23:58   作者:秋官  
在日常开发中,如果要操作数据库的话,或多或少都会遇到批量数据的处理,本文主要介绍了Mybatis批量插入的三种实现方法,感兴趣的可以了解一下

在日常开发中,如果要操作数据库的话,或多或少都会遇到批量数据的处理,我们公司使用的mybaits-plus作为持久层的框架,今天就简单介绍一下mybaits批量操作数据库的几种方式。

1.循环插入

其实这种方式并不是批量插入,只是在日常开发中,使用这种方式的还是比较多的。

@RunWith(SpringRunner.class)
@SpringBootTest
public class BatchTest {

    @Resource
    private StudentMapper studentMapper;


    @Test
    public void test(){
        List<Student> students = generateStudentData(100);

        long start = System.currentTimeMillis();
        students.forEach(studentMapper::insert);
        System.out.println("循环插入: " + students.size() + " 条数据,共计耗时:" + (System.currentTimeMillis() - start) + " 毫秒");
    }


    public static List<Student> generateStudentData(int size){
        List<Student> list = new ArrayList<>(size);
        Random random = new Random();
        for (int i = 0; i < size; i++) {
            Student student = new Student();
            student.setName("zhangsan-" + i);
            student.setAge(random.nextInt(40));
            student.setPhone("15077828899");
            student.setBirthday(LocalDateTime.now());

            list.add(student);
        }

        return list;
    }
}

2.foreach方式插入

@RunWith(SpringRunner.class)
@SpringBootTest
public class BatchTest {

    @Resource
    private StudentMapper studentMapper;


    @Test
    public void test3(){
        List<Student> students = generateStudentData(100);

        long foreachStart = System.currentTimeMillis();
        studentMapper.insertBatch(students);
        System.out.println("foreach插入: " + students.size() + " 条数据,共计耗时:" + (System.currentTimeMillis() - foreachStart) + " 毫秒");
    }


    public static List<Student> generateStudentData(int size){
        List<Student> list = new ArrayList<>(size);
        Random random = new Random();
        for (int i = 0; i < size; i++) {
            Student student = new Student();
            student.setName("zhangsan-" + i);
            student.setAge(random.nextInt(40));
            student.setPhone("15077828899");
            student.setBirthday(LocalDateTime.now());

            list.add(student);
        }

        return list;
    }
}

StudentMapper 接口如下:

public interface StudentMapper extends BaseMapper<Student> {

    /**
     * 批量插入
     */
    int insertBatch(@Param("entities") List<Student> entities);

    /**
     * 批量更新或者插入
     */
    int insertOrUpdateBatch(@Param("entities") List<Student> entities);

}

StudentMapper.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.efreight.oss.transfer.dao.StudentMapper">

    <resultMap type="com.efreight.oss.transfer.entity.Student" id="StudentMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="birthday" column="birthday" jdbcType="TIMESTAMP"/>
        <result property="phone" column="phone" jdbcType="VARCHAR"/>
    </resultMap>

    <!-- 批量插入 -->
    <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
        insert into cargo.student(name, age, birthday, phone)
        values
        <foreach collection="entities" item="entity" separator=",">
        (#{entity.name}, #{entity.age}, #{entity.birthday}, #{entity.phone})
        </foreach>
    </insert>

    <!-- 批量插入或按主键更新 -->
    <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
        insert into cargo.student(name, age, birthday, phone)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.name}, #{entity.age}, #{entity.birthday}, #{entity.phone})
        </foreach>
        on duplicate key update
        name = values(name) , age = values(age) , birthday = values(birthday) , phone = values(phone)
    </insert>

</mapper>

搭配 useGeneratedKeys="true" 和 keyProperty="id" 属性(这个id是javaBean的属性),可以获取自增主键,有时候这个主键我们是非常需要的。

3.批处理方式插入

通过 ExecutorType.BATCH来构建一个可以完成批处理工作的执行器

@RunWith(SpringRunner.class)
@SpringBootTest
public class BatchTest {

    @Resource
    private StudentMapper studentMapper;

    @Resource
    private SqlSessionTemplate sqlSessionTemplate;


    @Test
    public void test2(){
        List<Student> students = generateStudentData(100);

        long batchStart = System.currentTimeMillis();
        try(SqlSession sqlSession = this.sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false)) {
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            for (int i = 0; i < students.size(); i++) {  
                studentMapper.insert(students.get(i));  
                if (i % 1000 == 0 || i == students.size() - 1) {  
                sqlSession.flushStatements();  
                }  
            }  
            sqlSession.commit();
        }
        System.out.println("mybatis批处理插入: " + students.size() + " 条数据,共计耗时:" + (System.currentTimeMillis() - batchStart) + " 毫秒");
    }


    public static List<Student> generateStudentData(int size){
        List<Student> list = new ArrayList<>(size);
        Random random = new Random();
        for (int i = 0; i < size; i++) {
            Student student = new Student();
            student.setName("zhangsan-" + i);
            student.setAge(random.nextInt(40));
            student.setPhone("15077828899");
            student.setBirthday(LocalDateTime.now());

            list.add(student);
        }

        return list;
    }
}

注意:批处理方式是无法获取自增主键的。

顺便说一下,现在使用mybatis-plus的也非常多,他也提供了批量插入的功能,它内部使用的就是ExecutorType.BATCH 来构建的。

关于三者性能的比较大家可以跑下看看,循环插入的方式性能最差,能不用就尽量不用,在foreach和批处理中,我测试发现foreach的性能最好(我用的MySQL是5.7),所以项目中我们批处理使用的都是foreach, 因为一般我们一般批量插入最多也就2000条左右的数据,但是大家可以根据自己机器的实际情况,去跑一下看看。

插入方式100条1000条10000条10万条
循环插入1599 毫秒14336 毫秒140793 毫秒*
foreach62 毫秒364 毫秒3249 毫秒23940 毫秒
批处理321 毫秒6868 毫秒72851 毫秒457005 毫秒

到此这篇关于Mybatis批量插入的三种实现方法的文章就介绍到这了,更多相关Mybatis批量插入 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java中常见的中文乱码总结

    java中常见的中文乱码总结

    本文主要介绍了java中常见的中文乱码以及解决方法,主要包括字节码文件读取时出现的乱码问题,本文通过实例代码给大家介绍的非常详细,具有很好的参考价值,感兴趣的朋友跟随小编一起看看吧
    2017-03-03
  • 通过java.util.TreeMap源码加强红黑树的理解

    通过java.util.TreeMap源码加强红黑树的理解

    通过分析java.util.TreeMap源码来对经典问题红黑树加强理解和理清思路。
    2017-11-11
  • Java实现爬取百度图片的方法分析

    Java实现爬取百度图片的方法分析

    这篇文章主要介绍了Java实现爬取百度图片的方法,结合实例形式分析了java基于jsonp爬取百度图片的相关原理、操作技巧与注意事项,需要的朋友可以参考下
    2018-12-12
  • Java基本数据类型之间的相互转换详解

    Java基本数据类型之间的相互转换详解

    这篇文章主要讲解Java中基本数据类型的转换,数据之间相互转换是经常会用到的基础操作,文中讲的很清晰,希望能给大家做一个参考。
    2022-05-05
  • springboot关闭druid监控 druid2改配置文件无效的解决

    springboot关闭druid监控 druid2改配置文件无效的解决

    这篇文章主要介绍了springboot关闭druid监控 druid2改配置文件无效的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java缩小文件内存占用的方法技巧分享

    Java缩小文件内存占用的方法技巧分享

    在Java应用程序中,处理大文件时经常会遇到内存占用过高的问题,为了缩小文件的内存占用,我们可以采取一些有效的方法来优化和管理内存的使用,本文将介绍一些在Java中缩小文件内存占用的技巧,需要的朋友可以参考下
    2024-10-10
  • Java 利用枚举实现接口进行统一管理

    Java 利用枚举实现接口进行统一管理

    这篇文章主要介绍了Java 利用枚举实现接口进行统一管理,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • SpringMvc中的Bean加载机制详解

    SpringMvc中的Bean加载机制详解

    这篇文章主要介绍了SpringMvc中的Bean加载机制详解,在Spring MVC中,Bean的作用主要是处理应用程序的业务逻辑和数据,例如,一个用户管理应用程序的Bean可能包括UserService、UserDao和UserController等,需要的朋友可以参考下
    2023-12-12
  • 深入探究TimSort对归并排序算法的优化及Java实现

    深入探究TimSort对归并排序算法的优化及Java实现

    这篇文章主要介绍了TimSort归并排序的优化及Java实现,TimSort 是一个归并排序做了大量优化的版本,需要的朋友可以参考下
    2016-05-05
  • idea项目打开后出现橙色的时钟图标的解决

    idea项目打开后出现橙色的时钟图标的解决

    本文主要介绍了idea项目打开后出现橙色的时钟图标的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06

最新评论