MyBatis的强大特性之一便是它的动态SQL,这里主要说下<if>,<choose>,<where>,<set>,<foreach>,<bind>。搭建mybatis(基于springBoot)和增删改查,见上文
一、if
<select id="selectByUser" resultType="com.lbc.mybatisDemo.book.model.SysUser">
select * from sys_user where 1=1
<if test="userName !=null and userName !=''">
and user_name like concat('%',#{userName},'%')
</if>
<if test="userEmail !=null and userEmail !=''">
and user_email like concat('%',#{userEmail},'%')
</if>
</select>
if标签里的test是必填属性,该值应该是一个符合OGNL规范的判断表达式,该表达式返回的应该是true 或 false,除此之外所有的非0值均为true,只有0值为false。
判断条件property != null and property !=' ' 适用于任何object对象,而 property !=' ' 或 property == ' '只适应于String类型的字段。
SysUser sysUser = new SysUser();
sysUser.setUserName("my");
List<SysUser> query = userMapper.selectByUser(sysUser);
System.out.println(query);
insert、update同理使用。
二、choose
通过if标签的学习,我们也意识到了,好像if中并没有if···else···这种类型的判断,而在实际的开发中难免会遇到条件判断的情况,那choose的出现便弥补了这个缺陷,choose标签中含有<when>、<otherwise>两个标签,一个choose应该至少含有一个when标签。
<select id="selectByIdOrUserName" resultType="com.lbc.mybatisDemo.book.model.SysUser">
select * from sys_user where 1=1
<choose>
<when test="id != null">
and id = #{id}
</when>
<when test="userName !=null and userName !=''">
and user_name like concat('%',#{userName},'%')
</when>
<otherwise>
and 1 = 2
</otherwise>
</choose>
</select>
这是一个判断是否有id或userName属性的语句,要是两者全为空,则返回一个and 1=2(错误条件,导致选出的结果为空)
SysUser sysUser = new SysUser();
sysUser.setUserName("my");
List<SysUser> query = userMapper.selectByIdOrUserName(sysUser);
System.out.println(query);
三、where
<select id="selectByUserWhere" resultType="com.tiza.mybatisDemo.book.model.SysUser">
select * from sys_user
<where>
<if test="userName !=null and userName !=''">
and user_name like concat('%',#{userName},'%')
</if>
<if test="userEmail !=null and userEmail !=''">
and user_email like concat('%',#{userEmail},'%')
</if>
</where>
</select>
从中很容易看出,之前的where 1= 1 主要是为了防止if的所有语句都不适用,就会导致 select * from sys_user where 这样where没有条件,就会导致sql语句出错。有些开发人员不喜欢用1=1这种形式,那就可以直接用<where>标签,当<where>中的所有条件都不满足时,where也就随之不存在了。
四、set
<update id="updateByIdSelective">
update sys_user
<set>
<if test="userName !=null and userName !=''">
user_name= #{userName},
</if>
<if test="userPassword !=null and userPassword !=''">
user_password=#{userPassword},
</if>
<if test="userEmail !=null and userEmail !=''">
user_email=#{userEmail},
</if>
<if test="userInfo !=null and userInfo !=''">
user_info=#{userInfo},
</if>
<if test="headImg !=null and headImg !=''">
head_img = #{headImg,jdbcType = BLOB},
</if>
<if test="createTime !=null and createTime !=''">
create_time =#{createTime,jdbcType =TIMESTAMP}
</if>
</set>
where id = #{id}
</update>
set是将set值放在标签内,类似上文的where,用法也相似。
五、foreach
foreach是循环的语句,在mybatis中是一种集合的条件属性
<select id="selectByIdList" resultType="com.lbc.mybatisDemo.book.model.SysUser">
select * from sys_user where id in
<foreach collection="list" open="(" close=")" separator="," item="id" index="i">
#{id}
</foreach>
</select>
foreach包含以下属性
collection:必填 值为要迭代循环的属性名。
item:变量名,值为从迭代对象中取的每一个值。
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代循环的对象是Map类型时,这个值为Map的Key
open:整个循环内容开头的字符串。
close:整个循环内容结束的字符串。
separator:每次循环的分隔符。
collection对象中可以是集合list也可以是map对象
1、只有一个数组参数或集合参数时
DefaultSqlSession中wrapCollection方法如下:
private Object wrapCollection(Object object) {
DefaultSqlSession.StrictMap map;
if (object instanceof Collection) {
map = new DefaultSqlSession.StrictMap();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
map = new DefaultSqlSession.StrictMap();
map.put("array", object);
return map;
} else {
return object;
}
}
当参数为collection集合时,默认会转为一个key为collection的Map,若参数为list集合时,那么map的可以就为“list”(foreach标签中的collection = "list" 就可以得到这个list集合),当参数为数组时,也会转换为map,默认的key则会变成array。
注:使用@Param时指定名称,则collection要对应修改该名称。
List<SysUser> selectByIdList(List<Long> idArray);
List<SysUser> selectByIdList(@Param("custom") List<Long> idArray);
2、有多个参数时
@Param应该给每一个参数指定一个名称用于区分
3、参数为map时
使用map参数与@Param类似,要指定名称给collection,否则找不到对应的value,如不指定名称,默认的名称为_parameter。
4、参数为对象时
这种情况要指定对象的属性名,对象内多层嵌套的对象,要用属性.属性(集合和数组可以使用下标值),从而指定深层的属性值。
foreach中的批量插入
<insert id="insertList" >
insert into sys_user (user_name,user_password,user_email,user_info,head_img,create_time)
value
<foreach collection="list" item="user" separator=",">
(#{user.userName},#{user.userPassword},#{user.userEmail},#{user.userInfo},#{user.headImg,jdbcType = BLOB},#{user.createTime,jdbcType =TIMESTAMP})
</foreach>
</insert>
int insertList(List<SysUser> sysUsers);
List<SysUser> userList = new ArrayList<SysUser>();
for (int i = 0; i < 3; i++) {
SysUser user1 = new SysUser();
user1.setUserName("Test"+i);
user1.setUserPassword("123456");
user1.setUserEmail("1233@123.com");
userList.add(user1);
}
int row = userMapper.insertList(userList);
System.out.println(row);
foreach实现动态update
<update id="updateByMap">
update sys_user
set
<foreach collection="_parameter" item="val" index="key" separator=",">
${key} = #{val}
</foreach>
where id = #{id}
</update>
其中:
#{}这种方式SQL语句是经过预编译的
${}在动态解析时候,会传入参数字符串