MyBatis中批量操作foreach与BatchExecutor使用详解

简介: MyBatis中批量操作foreach与BatchExecutor使用详解

在MyBatis中批量操作,毋庸置疑离不开foreach。foreach 的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。

foreach 元素的属性主要有 item,index,collection,open,separator,close。


item 表示集合中每一个元素进行迭代时的别名;


index 指 定一个名字,用于表示在迭代过程中,每次迭代到的位置;


open 表示该语句以什么开始;


separator 表示在每次进行迭代之间以什么符号作为分隔 符;


close 表示以什么结束。


在使用 foreach 的时候最关键的也是最容易出错的就是collection 属性。


该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有以下3种情况:


① 如果传入的是单参数且参数类型是一个List的时候,collection 属性值为 list;


② 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为 array;


③ 如果传入的参数是多个的时候,我们就需要把它们封装成一个 Map ;


④ 自定义collection值


【1】mapper中不指定属性值

① 入参为List

即传入的是单参数且参数类型是一个List的时候,collection 属性值为 list

xml实例如下:

<insert id="addTrainRecordBatch" useGeneratedKeys="true" parameterType="java.util.List">
  <selectKey resultType="long" keyProperty="id" order="AFTER">
    SELECT
    LAST_INSERT_ID()
  </selectKey>
  insert into t_train_record (add_time,emp_id,activity_id,flag) 
  values
  <foreach collection="list" item="item" index="index" separator="," >
    (#{item.addTime},#{item.empId},#{item.activityId},#{item.flag})
  </foreach>
</insert>


另外一个批量保存应用实例

 <!-- 这种方式需要数据库连接属性allowMultiQueries=true;
    这种分号分隔多个sql可以用于其他的批量操作(删除,修改) 
jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
-->
<insert id="addEmps">
  <foreach collection="emps" item="emp" separator=";">
    insert into tbl_employee(last_name,email,gender,d_id)
    values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
  </foreach>
</insert> 


另外当使用动态SQL时 ,需要对list进行null 和空判断:

select * from sys_power where 1=1
<if test="powerIdList !=null and powerIdList.size > 0">
  and powerId in 
  <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
              #{item}
  </foreach>
</if>

② 入参为array

即,传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为 array

xml实例如下:

<select id="dynamicForeach2" resultType="hashmap">
        select * from t_blog where id in
        <foreach collection="array" index="index" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
</select>


③ 入参为map

xml实例如下:

<select id="dynamicForeach3" resultType="hashmap">
        select * from t_blog where title like "%"#{title}"%" and id in
        <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
</select>


上述collection的值为ids,是传入的参数Map的key。



【2】mapper中指定属性值

如果有多个参数不想封装为map呢?或者单个参数想自定义属性值呢?这时就可以在mapper中使用注解org.apache.ibatis.annotations.Param 进行指定,然后xml中使用即可。


mapper实例如下

int deleteBatchByIds(@Param("idList") List<Integer> idList);

XML实例如下

 <delete id="deleteBatchByIds" parameterType="java.util.List">
    delete from tb_sys_moment
    WHERE id IN
    <foreach collection="idList" open="(" close=")" separator="," item="itemId">
      #{itemId}
    </foreach>
  </delete>


【3】BatchExecutor

严格来讲上述操作并非MyBatis提供的批量操作处理。如下所示,批量插入数据时对应的xml实例。

<insert id="addEmps">
  insert into tbl_employee(<include refid="insertColumn"></include>) 
  values
  <foreach collection="emps" item="emp" separator=",">
    (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
  </foreach>
</insert>

其在MyBatis处理过程中会形成如下一条SQL语句:

insert into tbl_employee(
last_name,email,gender,d_id
) 
values
  (?,?,?,?)
 , 
  (?,?,?,?)

这种方式的批量插入虽然效率高于单次插入*n但是仍然小于MyBatis提供的BatchExecutor。


sqlsessionfactory默认的openSession() 方法没有参数,它会创建有如下特性的:


会开启一个事务(也就是不自动提交)

连接对象会从由活动环境配置的数据源实例得到。

事务隔离级别将会使用驱动或数据源的默认设置。

预处理语句不会被复用,也不会批量处理更新。

openSession 方法的ExecutorType类型的参数,枚举类型:


ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情(这是默认装配的)。它为每个语句的执行创建一个新的预处理语句。

ExecutorType.REUSE: 这个执行器类型会复用预处理语句。

ExecutorType.BATCH: 这个执行器会批量执行所有更新语句

批量操作我们是使用MyBatis提供的BatchExecutor进行的,他的底层就是通过jdbc攒sql的方式进行的。我们可以让他攒够一定数量后发给数据库一次。


测试实例如下:

public void test01() {
    //指定ExecutorType.BATCH创建sqlsession
  SqlSession openSession = build.openSession(ExecutorType.BATCH);
  UserDao mapper = openSession.getMapper(UserDao.class);
  longstart = System.currentTimeMillis();
  for(inti = 0; i < 1000000; i++) {
    String name = UUID.randomUUID().toString().substring(0, 5);
    mapper.addUser(newUser(null, name, 13));
  }
  openSession.commit();
  openSession.close();
  longend = System.currentTimeMillis();
  System.out.println("耗时时间:"+(end-start));
}

与Spring整合中,推荐额外的配置一个可以专门用来执行批量操作的sqlSession

<bean id="batchSqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
  <constructor-arg name="executorType" value="BATCH" ></constructor-arg>
</bean>

需要用到批量操作的时候,我们可以注入配置的这个批量SqlSession。通过他获取到mapper映射器进行操作。


需要注意的是:


批量操作是在session.commit()以后才发送sql语句给数据库进行执行的

如果我们想让其提前执行,以方便后续可能的查询操作获取数据,我们可以使用sqlSession.flushStatements()方法,让其直接冲刷到数据库进行执行。

三种批量插入措施


单次插入*n

foreach批量插入

BatchExecutor

通常根据数据量的不同,建议选择第二种或者第三种。第一种通常不推荐。

目录
相关文章
|
1月前
|
SQL XML Java
Mybatis中foreach的使用
【11月更文挑战第12天】MyBatis 的 `foreach` 标签用于在 SQL 语句中遍历集合或数组,支持批量插入、更新及多条件查询等操作。通过设置 `collection`、`item` 等属性,可动态生成 SQL 片段,实现高效的数据处理。示例包括批量插入用户信息、根据 ID 列表查询用户数据以及遍历 Map 查询分类下的产品。
|
3月前
|
SQL XML Java
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
文章介绍了MyBatis中动态SQL的用法,包括if、choose、where、set和trim标签,以及foreach标签的详细使用。通过实际代码示例,展示了如何根据条件动态构建查询、更新和批量插入操作的SQL语句。
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
|
7月前
|
Java 数据库连接 mybatis
mybatis判断批量操作是否全部执行成功
mybatis判断批量操作是否全部执行成功
204 1
|
SQL Java 数据库连接
MyBatis 如何执行批量操作?
MyBatis 如何执行批量操作?
73 0
|
SQL Java 数据库连接
MyBatis痛点验证,使用 foreach 批量插入慢?
MyBatis痛点验证,使用 foreach 批量插入慢?
419 0
|
7月前
|
SQL Java 数据库连接
mybatis 中 foreach collection的常用用法
mybatis 中 foreach collection的常用用法
226 1
Mybatis插入大量数据效率对比:foreach、SqlSession批量、sql
使用mybatis插入数据执行效率对比,对比三种方式(测试数据库为MySQL), 使用 SqlSessionFactory,每一批数据执行一次提交 使用mybatis-plus框架的insert方法,for循环,每次执行一次插入 使用ibatis,纯sql插入
|
SQL Java 数据库连接
63MyBatis - foreach元素(复习)
63MyBatis - foreach元素(复习)
63 0
|
SQL 存储 Java
31MyBatis - 动态SQL的 foreach标签
31MyBatis - 动态SQL的 foreach标签
57 0
|
SQL XML Java
mybatis动态sql&choose&foreach&sql 及include & sql中的特殊字符&后台分页实现& 数据版本号处理并发问题
mybatis动态sql&choose&foreach&sql 及include & sql中的特殊字符&后台分页实现& 数据版本号处理并发问题