Mybatis学习四(动态SQL)_ide​​

    Mybatis的强大特性之一便是它的动态SQL,它帮助我们很好的完成SQL语句的拼接。我们来学习一下MyBatis的动态SQL在XML中的几种标签。


一、if用法

        if标签通常用在WHERE条件语句中,通过判断参数值来决定是否使用某个查询条件,它也经常用于UPDATE语句中判断是否更新某一个字段,也可以在INSERT语句中用来判断是否插入某个字段的值。

    1、在WHERE条件中使用if

            需求:输入用户名时,根据用户名模糊查询;输入邮箱时,根据邮箱精确匹配;都输入时,两个条件都用。

       Mapper接口添加方法如下:

List<SysUser> selectByNameAndEmail(@Param("userName")String userName,@Param("userEmail")String userEmail);

        Mapper文件添加如下:

<!--if标签的使用,if标签有一个必填的test属性,是一个符合OGNL的表达式,结果可以是true或false,所有的非0都为true,0为false。-->
<select id="selectByNameAndEmail" resultType="SysUser">
SELECT id,user_name,user_password,user_email,user_info,head_img,create_time
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 = #{userEmail}
</if>
</select>

        测试可用,1=1 是为了避免生成不正确的SQL(两个if都不符合时,多出来一个WHERE),可以在后续使用where标签。

    2、在UPDATE中使用if

       需求:只更新发生变化的字段

    Mapper接口添加如下:

/**
* 一般情况下MyBatis中选择性更新方法名会以Selective作为后缀
*/
int updateByIdSelective(SysUser sysUser);

    Mapper文件添加如下:

<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">
head_img = #{headImg},
</if>
<if test="createTime != null">
create_time = #{createTime},
</if>
id = #{id}
WHERE id = #{id}
</update>

    测试可用,set中 id=#{id}的作用是防止SQL拼接错误,后续可以使用set标签。

    3、在INSERT动态插入列中使用if

            需求:插入参数不为空的值

    Mapper接口添加如下:

int insertUser(SysUser sysUser);

    Mapper文件添加如下:

<!--在列的部分增加if时,在VALUES中也要添加相同的if-->
<insert id="insertUser">
INSERT INTO sys_user(user_name,
<if test="userPassword != null and userPassword != ''">
user_password,
</if>
user_email,user_info, head_img, create_time
) VALUES (#{userName},
<if test="userPassword != null and userPassword != ''">
#{userPassword},
</if>
#{userEmail},#{userInfo}, #{headImg}, #{createTime})
</insert>

        测试可用。


二、choose用法

    if标签提供了基本的条件判断,但是它没办法实现if...else、if...else...的逻辑,想实现这样的逻辑就需要用到choose when otherwise 标签。choose中包含when和otherwise两个标签,一个choose中至少有一个when,0或1个otherwise。

    需求:当有id的时候用id查询,没有id时,用用户名查询,都没有,使SQL查询无果。

    Mapper接口添加如下:

SysUser selectByIdOrUserName(@Param("id")Long id,@Param("userName") String userName);

    Mapper文件添加如下:

<select id="selectByIdOrUserName" resultType="SysUser">
SELECT * FROM sys_user WHERE
<choose>
<when test="id != null and id != ''">
id = #{id}
</when>
<when test="userName != null and userName != ''">
user_name = #{userName}
</when>
<otherwise>
1=2
</otherwise>
</choose>

</select>

    测试可用


三、where用法

       where标签作用:如果该标签包含的元素有返回值,就插入一个where;如果where后面的字符串使以AND和OR开头的,就将它们剔除。

        需求:使用where标签修改一、1中的Mapper文件

<select id="selectByNameAndEmail" resultType="SysUser">
SELECT id,user_name,user_password,user_email,user_info,head_img,create_time
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 = #{userEmail}
</if>
</where>
</select>


四、set用法

    set标签作用:如果该标签包含的元素中有返回值,就插入一个set;如果set后面的字符串是以逗号结尾的,就将这个逗号删除。但是如果set中没有内容,照样会出现SQL错误,为避免错误的产生,类似id=#{id}这样必然存在的值仍然有保留的必要。

    需求:修改一、2中的Mapper文件 

<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">
head_img = #{headImg},
</if>
<if test="createTime != null">
create_time = #{createTime},
</if>
id = #{id}
</set>
WHERE id = #{id}
</update>


 五、trim用法

        where和set标签的功能都可以用trim实现,在底层就是通过TrimeSqlNode实现的。

        trim属性如下:

            prefix : 当trim元素内包含内容时,会给内容增加prefix指定的前缀。

            prefixOverrides : 当trim元素内包含内容时,会把内同中匹配的前缀字符串去掉。

            suffix :当trim元素内包含内容时,会给内容增加指定的后缀。

            suffixOverrides : 当trim元素内包含内容时,会把内同中匹配的后缀字符串去掉。

        where标签对应的trim实现如下:

<trim prefix="WHERE" prefixOverrides="AND | OR " >
...
</trim>

        set标签对应的trim实现如下:

<trim prefix="SET" suffixOverrides="," >
...
</trim>


六、foreach用法

        属性:

            collection : 必填,值为要迭代循环的属性名。

            item : 变量名,值为从迭代对象中取出的每一个值。

            index : 索引属性名,在集合数组情况下值为当前索引值,在迭代循环的对象时map时,为map的key。

            open : 循环开头的字符串。

            close :循环结束的字符串。

            separator : 每次循环的分隔符。

    1、foreach实现in集合

        需求:根据id集合查询用户

Mapper接口添加如下:

List<SysUser> selectByIdList(@Param("ids") List<Long> ids);

Mapper文件添加如下:

<select id="selectByIdList" resultType="SysUser">
SELECT * FROM sys_user WHERE id IN
<foreach collection="ids" open="(" close=")" item="id" separator="," index="i">
#{id}
</foreach>
</select>

使用@Param指定参数的名字,没有那么多事,什么List集合要用list,数组要用array。

    2、foreach实现批量插入

    需求:批量插入用户信息

Mapper接口添加如下:

int insertList(@Param("userList")List<SysUser> userList);

Mapper文件添加如下:

<insert id="insertList">
INSERT INTO sys_user(user_name,user_password,user_email,user_info,head_img,create_time)
VALUES
<foreach collection="userList" item="user" separator=",">
(#{user.userName},#{user.userPassword},#{user.userEmail},#{user.userInfo},#{user.headImg},#{user.createTime})
</foreach>
</insert>

    测试可用

    3、foreach实现动态UPDATE

        需求:使用map作为参数修改

Mapper接口:

int updateByMap(Map<String,Object> map);

Mapper文件:

<!--MyBatis在内部上下文中使用了默认值_parameter作为参数key。-->
<update id="updateByMap">
UPDATE sys_user SET
<foreach collection="_parameter" item="val" index="key" separator=",">
${key} = #{val}
</foreach>
WHERE id = #{id}
</update>


源码:https://gitee.com/itcaofanqi/CaoFanqiStudyRepository/tree/master/stumybatis