MyBatis如何执行批量操作?

MyBatis如何执行批量操作?
第一种方法:使用foreach标签
在构建SQL语句中的IN条件时,我们可以使用foreach标签来迭代一个集合。foreach标签有一些属性,包括item、index、collection、open、separator和close。
- item:表示在迭代过程中集合中每个元素的别名,可以自定义变量名。
- index:指定一个名字,用于表示迭代的位置,不常用。
- collection:指定要迭代的集合,这是必须指定的属性。
- open:指定SQL语句的开始部分,常用的是"("。
- separator:指定每次迭代之间的分隔符,常用的是","。
- close:指定SQL语句的结束部分,常用的是")"。
在使用foreach标签时,最关键且容易出错的是collection属性的值。根据不同的情况,collection属性有以下三种取值方式:
- 如果传入的是单参数且参数类型是List,那么collection属性的值为list。
- 如果传入的是单参数且参数类型是数组,那么collection属性的值为array。
- 如果传入的是多个参数,我们需要将它们封装成一个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>