1. foreach 标签的应用
foreach标签有几个属性,collection、item、index、separator、open以及close.
- item:集合中元素迭代时的别名,该参数为必选。
- index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选
- open:foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选
- separator:元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
- close: foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。
- collection: 要做foreach的对象,作为入参时,List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键。当然在作为入参时可以使用@Param(“keyName”)来设置键,设置keyName后,list,array将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = “ids”.如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id"
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
-
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .
-
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
-
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.
-
还会有一种情况,如果list设置了@Param,则collection应该为value的值.
例如:
<insert id="insert" parameterType="java.util.List">
insert INTO TABLE(SOURCE,REGION)
<foreach collection="list" item="item" index="index" separator="union all" >
#{item.source},
#{item.region}
</foreach>
</insert>
<update id="delPanChanMenuRel">
update table set is_valid = '0'
where menu_id in
<foreach collection="menuIds" item="item" index="index" separator="," close=")" open="(">
#{item}
</foreach>
</update>
参考原文:https://www.cnblogs.com/fnlingnzb-learner/p/10566452.html
2. trim的应用
foreach拼接组成的sql在一些情况下不适用,比如在update的时候set的属性值也在list中就无法使用foreach拼成正确的sql。如果在dao层进行循环则会大大降低效率,这是不允许的。我在寻找批量操作的方法时发现了trim的方式,以case when的形式,结合foreach使用。
trim标签的属性prefix、suffix、prefixOverrides、suffixOverrides
- prefix:给sql语句拼接的前缀
- suffix:给sql语句拼接的后缀
- prefixOverrides:去除sql语句前面的关键字或者字符,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
- suffixOverrides:去除sql语句后面的关键字或者字符
<!-- 批量更新第二种方法,通过 case when语句变相的进行批量更新 -->
<update id="updateCaseByUserId" parameterType="java.util.List">
update lp_user_test_batch
<trim prefix="set" suffixOverrides=",">
<!-- 拼接case when 这是另一种写法 -->
<trim prefix="user_name =case" suffix="end,">
<foreach collection="list" item="item">
<if test="item.userName!=null">
when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.userName,jdbcType=VARCHAR}
</if>
</foreach>
</trim>
<trim prefix="user_age =case" suffix="end,">
<foreach collection="list" item="item">
<if test="item.userAge!=null">
when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.userAge,jdbcType=INTEGER}
</if>
</foreach>
</trim>
<trim prefix="type =case" suffix="end,">
<foreach collection="list" item="item">
<if test="item.type!=null">
when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.type,jdbcType=INTEGER}
</if>
</foreach>
</trim>
<trim prefix="update_time =case" suffix="end,">
<foreach collection="list" item="item">
<if test="item.type!=null">
when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.updateTime,jdbcType=TIMESTAMP}
</if>
</foreach>
</trim>
</trim>
<where>
user_id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.userId,jdbcType=VARCHAR}
</foreach>
</where>
</update>
3. BATCH模式 sqlSession和SqlSessionFactory
公司大佬告诉我有这个方式,但是这个比较复杂,我也没有吃懂,建议参考链接https://blog.youkuaiyun.com/u013412772/article/details/73648537
在全局配置文件的setting中,有一个属性可以设置ExecutorType的类型,默认为SIMPLE,但是通常我们不会在全局配置文件中进行设置。
在使用中,通常在获取SqlSession的时候加以参数进行配置,SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);,以往我们都是使用不带参数的进行打开Session,这里使用带参数的进行获取,可以获取到支持批量操作的SqlSession。BATCH模式,只发出一条SQL语句,预编译一次,但设置参数N次,执行一次。