MyBatis如何执行批量操作?

第一种方法:使用foreach标签

在构建SQL语句中的IN条件时,我们可以使用foreach标签来迭代一个集合。foreach标签有一些属性,包括item、index、collection、open、separator和close。

  • item:表示在迭代过程中集合中每个元素的别名,可以自定义变量名。
  • index:指定一个名字,用于表示迭代的位置,不常用。
  • collection:指定要迭代的集合,这是必须指定的属性。
  • open:指定SQL语句的开始部分,常用的是"("。
  • separator:指定每次迭代之间的分隔符,常用的是","。
  • close:指定SQL语句的结束部分,常用的是")"。

在使用foreach标签时,最关键且容易出错的是collection属性的值。根据不同的情况,collection属性有以下三种取值方式:

  1. 如果传入的是单参数且参数类型是List,那么collection属性的值为list。
  2. 如果传入的是单参数且参数类型是数组,那么collection属性的值为array。
  3. 如果传入的是多个参数,我们需要将它们封装成一个Map。实际上,即使是单参数,在MyBatis内部也会将其封装成一个Map,其中Map的key是参数名。这种情况下,collection属性的值就是封装后的Map中List或数组对象的key。

看看批量保存的两种用法:

<!-- MySQL下批量保存,可以foreach遍历 mysql支持values(),(),()语法 --> //推荐使用
<insert id="addEmpsBatch">
    INSERT INTO emp(ename,gender,email,did)
    VALUES
    <foreach collection="emps" item="emp" separator=",">
        (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
    </foreach>
</insert>
<!-- 这种方式需要数据库连接属性allowMutiQueries=true的支持
 如jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true -->  
<insert id="addEmpsBatch">
    <foreach collection="emps" item="emp" separator=";">                                 
        INSERT INTO emp(ename,gender,email,did)
        VALUES(#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
    </foreach>
</insert>

第二种方法:使用ExecutorType.BATCH

  • Mybatis内置的ExecutorType有3种,默认为simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优; 但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,在某些情况下不符合业务的需求。

具体用法如下:

//批量保存方法测试
@Test  
public void testBatch() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    //可以执行批量操作的sqlSession
    SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

    //批量保存执行前时间
    long start = System.currentTimeMillis();
    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 1000; i++) {
            mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1"));
        }

        openSession.commit();
        long end = System.currentTimeMillis();
        //批量保存执行后的时间
        System.out.println("执行时长" + (end - start));
        //批量 预编译sql一次==》设置参数==》10000次==》执行1次   677
        //非批量  (预编译=设置参数=执行 )==》10000次   1121

    } finally {
        openSession.close();
    }
}
  • mapper和mapper.xml如下
public interface EmployeeMapper {   
    //批量保存员工
    Long addEmp(Employee employee);
}
<mapper namespace="com.jourwon.mapper.EmployeeMapper"
     <!--批量保存员工 -->
    <insert id="addEmp">
        insert into employee(lastName,email,gender)
        values(#{lastName},#{email},#{gender})
    </insert>
</mapper>

标签: java, Java面试题, mybatis, Java问题合集, Java编程, Java问题精选, Java常见问题, MyBatis面试题