在实际生产开发中,我们都知道,DB是影响响应速度的主要原因之一,因此都会选择尽可能减少操作DB的次数,所以在批量操作数据库时,都会选择一些方式去尽可能优化。
一、实体类和mapper
实体类为:
@Data
public class User {
private Long userId;
private String name;
private String gender;
private Date createTime;
}
UserMapper中的方法声明:
// 批量插入
int batchInsertUser(List<User> users);
// 批量更新
int batchUpdateUser(List<User> users);
二、批量插入xml
批量插入对应的xml中SQL语句的拼接如下:
<insert id="batchInsertUser" parameterType="java.util.List">
insert into tb_user (
user_id, name, gender, create_time
) values
<foreach collection="users" item="user" separator=",">
(
<if test="user.userId != null and user.userId != 0">#{user.userId},</if>
<if test="user.name != null and user.name != ''">#{user.name},</if>
<if test="user.gender != null and user.gender != ''">#{user.gender},</if>
sysdate()
)
</foreach>
</insert>
2.1 <insert/>标签
其中,<insert/>标签中id字段对应mapper接口中声明的方法名,parameterType对应的是方法入参类型。
2.2 <foreach>标签
2.2.1collection属性
表示迭代的数据源从哪来,如果mapper接口的方法入参设置了变量别名,必须与其一致,否则,写list,Mybatis默认为list。
2.2.2item属性
循环中迭代的变量,就是Java中增强for循环的变量定义类似。
2.2.3index属性
循环的索引,表示第几次循环
2.2.4separator属性
分割器,拼接的SQL语句中需要用啥拼接就写啥,在插入中,value内,每组值用“,”分开,所以此处用“,”。
三、批量更新xml
批量更新跟相对复杂,因为更新时,需要匹配到指定的数据记录,才能进行。
主要思想是使用case when关键字,最后拼接成一条SQL语句执行。
<update id="batchUpdateUser" parameterType="java.util.List">
update tb_user
<trim prefix="set" suffixOverrides=",">
<trim prefix="name = case" suffix="end,">
<foreach collection="users" index="index" item="user">
<if test="user.name != null and user.name != ''">
when user_id = #{user.userId} then #{user.name}
</if>
</foreach>
</trim>
<trim prefix="gender = case" suffix="end,">
<foreach collection="users" index="index" item="user">
<if test="user.gender != null and user.gender != ''">
when user_id = #{user.userId} then #{user.gender}
</if>
</foreach>
</trim>
update_time = sysdate()
</trim>
where
<foreach collection="users" index="index" item="user" separater="or">
user_id = #{user.userId}
</foreach>
</update>
3.1<trim>标签
3.1.1prefix属性
前缀,通常就是需要修改字段对应数据库表中的字段名。
3.1.2suffix属性
后缀,每次循环结束,添加“end,”关键字,并且每个case之间用逗号隔开。
3.2 <if>标签
进行list中每个对象的属性判断,先判断该属性对象是否为空,不为空时,若是整型,判断是否为0,若是字符串,判断是否为空。切记!!不能把字符串判断是否为0,否则报错。
3.3 注意点
更新操作比较繁琐,需要更新多少个字段,就要写多少个trim。
四、缺陷
这种拼接成一条SQL语句执行的方式也存在不足,当List足够大时(大约拼接的SQL占用内存为10M左右时),会报错。最佳的方式是用mybatis-plus的批量操作,其底层设定了一次操作的最大记录为1000。当然,也可以参照mybatis-plus的思路对Mybatis进行定制化,需要自己写点Java代码处理。